2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2013-10-16 06:10:04 +02:00
|
|
|
|
2015-12-03 21:13:37 +01:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/resource.h>
|
2013-08-12 00:35:49 +02:00
|
|
|
#include <sys/socket.h>
|
2015-12-03 21:13:37 +01:00
|
|
|
#include <unistd.h>
|
2013-08-12 00:35:49 +02:00
|
|
|
|
2015-10-23 18:52:53 +02:00
|
|
|
#include "sd-bus.h"
|
2014-12-29 12:41:26 +01:00
|
|
|
#include "sd-daemon.h"
|
|
|
|
#include "sd-event.h"
|
2015-12-03 21:13:37 +01:00
|
|
|
#include "sd-id128.h"
|
2015-09-11 16:48:24 +02:00
|
|
|
|
2020-08-22 18:48:03 +02:00
|
|
|
#include "bus-common-errors.h"
|
2015-09-11 16:48:24 +02:00
|
|
|
#include "bus-internal.h"
|
|
|
|
#include "bus-label.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "bus-util.h"
|
2019-06-20 20:07:01 +02:00
|
|
|
#include "path-util.h"
|
2020-01-22 11:39:22 +01:00
|
|
|
#include "socket-util.h"
|
2015-10-27 01:26:31 +01:00
|
|
|
#include "stdio-util.h"
|
2013-10-16 06:10:04 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
2013-10-16 06:10:04 +02:00
|
|
|
sd_event *e = userdata;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(e);
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
sd_bus_close(sd_bus_message_get_bus(m));
|
2013-12-12 22:21:25 +01:00
|
|
|
sd_event_exit(e, 0);
|
2014-06-05 13:31:25 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-12-12 22:21:25 +01:00
|
|
|
int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
|
2017-12-19 12:29:04 +01:00
|
|
|
const char *match;
|
2013-12-12 21:25:47 +01:00
|
|
|
const char *unique;
|
2013-10-16 06:10:04 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(e);
|
|
|
|
assert(bus);
|
|
|
|
assert(name);
|
|
|
|
|
2013-12-12 22:21:25 +01:00
|
|
|
/* We unregister the name here and then wait for the
|
|
|
|
* NameOwnerChanged signal for this event to arrive before we
|
|
|
|
* quit. We do this in order to make sure that any queued
|
|
|
|
* requests are still processed before we really exit. */
|
|
|
|
|
2013-12-12 21:25:47 +01:00
|
|
|
r = sd_bus_get_unique_name(bus, &unique);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-12-19 12:29:04 +01:00
|
|
|
match = strjoina(
|
|
|
|
"sender='org.freedesktop.DBus',"
|
|
|
|
"type='signal',"
|
|
|
|
"interface='org.freedesktop.DBus',"
|
|
|
|
"member='NameOwnerChanged',"
|
|
|
|
"path='/org/freedesktop/DBus',"
|
|
|
|
"arg0='", name, "',",
|
|
|
|
"arg1='", unique, "',",
|
|
|
|
"arg2=''");
|
|
|
|
|
|
|
|
r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-12-19 12:29:04 +01:00
|
|
|
r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-19 21:14:52 +01:00
|
|
|
int bus_event_loop_with_idle(
|
|
|
|
sd_event *e,
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *name,
|
|
|
|
usec_t timeout,
|
|
|
|
check_idle_t check_idle,
|
|
|
|
void *userdata) {
|
2013-10-16 06:10:04 +02:00
|
|
|
bool exiting = false;
|
2013-12-12 22:21:25 +01:00
|
|
|
int r, code;
|
2013-10-16 06:10:04 +02:00
|
|
|
|
|
|
|
assert(e);
|
|
|
|
assert(bus);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
for (;;) {
|
2013-12-19 21:14:52 +01:00
|
|
|
bool idle;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = sd_event_get_state(e);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == SD_EVENT_FINISHED)
|
|
|
|
break;
|
|
|
|
|
2013-12-19 21:14:52 +01:00
|
|
|
if (check_idle)
|
|
|
|
idle = check_idle(userdata);
|
|
|
|
else
|
|
|
|
idle = true;
|
|
|
|
|
|
|
|
r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-13 16:20:45 +01:00
|
|
|
if (r == 0 && !exiting && idle) {
|
2020-03-18 16:36:14 +01:00
|
|
|
/* Inform the service manager that we are going down, so that it will queue all
|
|
|
|
* further start requests, instead of assuming we are already running. */
|
|
|
|
sd_notify(false, "STOPPING=1");
|
2014-06-05 13:31:25 +02:00
|
|
|
|
2020-03-18 16:36:14 +01:00
|
|
|
r = bus_async_unregister_and_exit(e, bus, name);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-03-18 16:36:14 +01:00
|
|
|
exiting = true;
|
|
|
|
continue;
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-12 22:21:25 +01:00
|
|
|
r = sd_event_get_exit_code(e, &code);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return code;
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
|
|
|
|
2013-11-28 14:50:19 +01:00
|
|
|
int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
|
2013-11-28 14:50:19 +01:00
|
|
|
int r, has_owner = 0;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
r = sd_bus_call_method(c,
|
|
|
|
"org.freedesktop.DBus",
|
|
|
|
"/org/freedesktop/dbus",
|
|
|
|
"org.freedesktop.DBus",
|
|
|
|
"NameHasOwner",
|
|
|
|
error,
|
|
|
|
&rep,
|
|
|
|
"s",
|
|
|
|
name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_message_read_basic(rep, 'b', &has_owner);
|
|
|
|
if (r < 0)
|
|
|
|
return sd_bus_error_set_errno(error, r);
|
|
|
|
|
|
|
|
return has_owner;
|
|
|
|
}
|
|
|
|
|
2020-08-22 18:48:03 +02:00
|
|
|
bool bus_error_is_unknown_service(const sd_bus_error *error) {
|
|
|
|
return sd_bus_error_has_names(error,
|
|
|
|
SD_BUS_ERROR_SERVICE_UNKNOWN,
|
|
|
|
SD_BUS_ERROR_NAME_HAS_NO_OWNER,
|
|
|
|
BUS_ERROR_NO_SUCH_UNIT);
|
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
int bus_check_peercred(sd_bus *c) {
|
2013-08-12 00:35:49 +02:00
|
|
|
struct ucred ucred;
|
2017-12-30 15:20:38 +01:00
|
|
|
int fd, r;
|
2013-08-12 00:35:49 +02:00
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
fd = sd_bus_get_fd(c);
|
2013-10-30 13:52:40 +01:00
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
2013-08-12 00:35:49 +02:00
|
|
|
|
2017-12-30 15:20:38 +01:00
|
|
|
r = getpeercred(fd, &ucred);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-08-12 00:35:49 +02:00
|
|
|
|
|
|
|
if (ucred.uid != 0 && ucred.uid != geteuid())
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-09-24 13:30:10 +02:00
|
|
|
int bus_connect_system_systemd(sd_bus **_bus) {
|
2019-01-17 16:07:22 +01:00
|
|
|
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
|
2013-08-12 00:35:49 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(_bus);
|
|
|
|
|
2013-10-30 13:52:40 +01:00
|
|
|
if (geteuid() != 0)
|
2015-09-24 13:30:10 +02:00
|
|
|
return sd_bus_default_system(_bus);
|
2013-08-12 14:19:22 +02:00
|
|
|
|
2017-07-23 17:45:57 +02:00
|
|
|
/* If we are root then let's talk directly to the system
|
|
|
|
* instance, instead of going via the bus */
|
2013-12-03 19:55:51 +01:00
|
|
|
|
|
|
|
r = sd_bus_new(&bus);
|
2013-10-30 13:52:40 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-08-12 14:19:22 +02:00
|
|
|
|
2013-12-03 19:55:51 +01:00
|
|
|
r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_start(bus);
|
|
|
|
if (r < 0)
|
2015-09-24 13:30:10 +02:00
|
|
|
return sd_bus_default_system(_bus);
|
2013-12-03 19:55:51 +01:00
|
|
|
|
2013-10-30 13:52:40 +01:00
|
|
|
r = bus_check_peercred(bus);
|
2013-08-12 14:19:22 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*_bus = TAKE_PTR(bus);
|
2013-10-30 13:52:40 +01:00
|
|
|
|
2013-08-12 14:19:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 13:30:10 +02:00
|
|
|
int bus_connect_user_systemd(sd_bus **_bus) {
|
2019-01-17 16:07:22 +01:00
|
|
|
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
|
2013-12-03 19:55:51 +01:00
|
|
|
_cleanup_free_ char *ee = NULL;
|
2013-11-08 17:07:07 +01:00
|
|
|
const char *e;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(_bus);
|
|
|
|
|
|
|
|
e = secure_getenv("XDG_RUNTIME_DIR");
|
2013-12-01 18:17:21 +01:00
|
|
|
if (!e)
|
2015-09-24 13:30:10 +02:00
|
|
|
return sd_bus_default_user(_bus);
|
2013-12-01 18:17:21 +01:00
|
|
|
|
2013-12-03 19:55:51 +01:00
|
|
|
ee = bus_address_escape(e);
|
|
|
|
if (!ee)
|
2013-12-01 18:17:21 +01:00
|
|
|
return -ENOMEM;
|
2013-11-08 17:07:07 +01:00
|
|
|
|
|
|
|
r = sd_bus_new(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-10-23 17:43:27 +02:00
|
|
|
bus->address = strjoin("unix:path=", ee, "/systemd/private");
|
2013-12-03 19:55:51 +01:00
|
|
|
if (!bus->address)
|
|
|
|
return -ENOMEM;
|
2013-11-08 17:07:07 +01:00
|
|
|
|
|
|
|
r = sd_bus_start(bus);
|
|
|
|
if (r < 0)
|
2015-09-24 13:30:10 +02:00
|
|
|
return sd_bus_default_user(_bus);
|
2013-11-08 17:07:07 +01:00
|
|
|
|
|
|
|
r = bus_check_peercred(bus);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*_bus = TAKE_PTR(bus);
|
2013-11-08 17:07:07 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-22 17:21:27 +02:00
|
|
|
int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
|
2019-01-17 16:07:22 +01:00
|
|
|
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
|
2013-10-30 16:44:55 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(transport >= 0);
|
|
|
|
assert(transport < _BUS_TRANSPORT_MAX);
|
2016-08-22 17:21:27 +02:00
|
|
|
assert(ret);
|
2013-10-30 16:44:55 +01:00
|
|
|
|
|
|
|
assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
|
2015-03-13 14:08:00 +01:00
|
|
|
assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
|
2013-10-30 16:44:55 +01:00
|
|
|
|
|
|
|
switch (transport) {
|
|
|
|
|
|
|
|
case BUS_TRANSPORT_LOCAL:
|
|
|
|
if (user)
|
2016-08-22 17:21:27 +02:00
|
|
|
r = sd_bus_default_user(&bus);
|
2018-05-09 10:06:46 +02:00
|
|
|
else {
|
2020-10-09 14:59:44 +02:00
|
|
|
if (sd_booted() <= 0)
|
2018-05-09 10:06:46 +02:00
|
|
|
/* Print a friendly message when the local system is actually not running systemd as PID 1. */
|
2020-10-09 14:59:44 +02:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
|
|
|
|
"System has not been booted with systemd as init system (PID 1). Can't operate.");
|
2018-05-09 10:06:46 +02:00
|
|
|
r = sd_bus_default_system(&bus);
|
|
|
|
}
|
2013-10-30 16:44:55 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BUS_TRANSPORT_REMOTE:
|
2016-08-22 17:21:27 +02:00
|
|
|
r = sd_bus_open_system_remote(&bus, host);
|
2013-11-08 17:07:07 +01:00
|
|
|
break;
|
|
|
|
|
2014-12-23 23:38:13 +01:00
|
|
|
case BUS_TRANSPORT_MACHINE:
|
2016-08-22 17:21:27 +02:00
|
|
|
r = sd_bus_open_system_machine(&bus, host);
|
2013-11-08 17:07:07 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Hmm, unknown transport type.");
|
|
|
|
}
|
2016-08-22 17:21:27 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-11-08 17:07:07 +01:00
|
|
|
|
2016-08-22 17:21:27 +02:00
|
|
|
r = sd_bus_set_exit_on_disconnect(bus, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(bus);
|
2016-08-22 17:21:27 +02:00
|
|
|
|
|
|
|
return 0;
|
2013-11-08 17:07:07 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 13:30:10 +02:00
|
|
|
int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
|
2013-11-08 17:07:07 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(transport >= 0);
|
|
|
|
assert(transport < _BUS_TRANSPORT_MAX);
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
|
2015-03-13 14:08:00 +01:00
|
|
|
assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
|
2013-11-08 17:07:07 +01:00
|
|
|
|
|
|
|
switch (transport) {
|
|
|
|
|
|
|
|
case BUS_TRANSPORT_LOCAL:
|
|
|
|
if (user)
|
2015-09-24 13:30:10 +02:00
|
|
|
r = bus_connect_user_systemd(bus);
|
2018-05-09 10:06:46 +02:00
|
|
|
else {
|
2018-11-20 23:40:44 +01:00
|
|
|
if (sd_booted() <= 0)
|
2018-05-09 10:06:46 +02:00
|
|
|
/* Print a friendly message when the local system is actually not running systemd as PID 1. */
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
|
|
|
|
"System has not been booted with systemd as init system (PID 1). Can't operate.");
|
2018-05-09 10:06:46 +02:00
|
|
|
r = bus_connect_system_systemd(bus);
|
|
|
|
}
|
2013-11-08 17:07:07 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BUS_TRANSPORT_REMOTE:
|
2014-02-18 19:11:08 +01:00
|
|
|
r = sd_bus_open_system_remote(bus, host);
|
2013-10-30 16:44:55 +01:00
|
|
|
break;
|
|
|
|
|
2014-12-23 23:38:13 +01:00
|
|
|
case BUS_TRANSPORT_MACHINE:
|
|
|
|
r = sd_bus_open_system_machine(bus, host);
|
2013-10-30 16:44:55 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Hmm, unknown transport type.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2013-11-05 00:50:34 +01:00
|
|
|
|
bus: implement bus_path_{en,de}code_unique()
Whenever we provide a bus API that allows clients to create and manage
server-side objects, we need to provide a unique name for these objects.
There are two ways to provide them:
1) Let the server choose a name and return it as method reply.
2) Let the client pass its name of choice in the method arguments.
The first method is the easiest one to implement. However, it suffers from
a race condition: If a client creates an object asynchronously, it cannot
destroy that object until it received the method reply. It cannot know the
name of the new object, thus, it cannot destroy it. Furthermore, this
method enforces a round-trip. If the client _depends_ on the method call
to succeed (eg., it would close() the connection if it failed), the client
usually has no reason to wait for the method reply. Instead, the client
can immediately schedule further method calls on the newly created object
(in case the API guarantees in-order method-call handling).
The second method fixes both problems: The client passes an object name
with the method-call. The server uses it to create the object. Therefore,
the client can schedule object destruction even if the object-creation
hasn't finished, yet (again, requiring in-order method-call handling).
Furthermore, the client can schedule further method calls on the newly
created object, before the constructor returned.
There're two problems to solve, though:
1) Object names are usually defined via dbus object paths, which are
usually globally namespaced. Therefore, multiple clients must be able
to choose unique object names without interference.
2) If multiple libraries share the same bus connection, they must be
able to choose unique object names without interference.
The first problem is solved easily by prefixing a name with the
unique-bus-name of a connection. The server side must enforce this and
reject any other name.
The second problem is solved by providing unique suffixes from within
sd-bus. As long as sd-bus always returns a fresh new ID, if requested,
multiple libraries will never interfere. This implementation re-uses
bus->cookie as ID generator, which already provides unique IDs for each
bus connection.
This patch introduces two new helpers:
bus_path_encode_unique(sd_bus *bus,
const char *prefix,
const char *sender_id,
const char *external_id,
char **ret_path);
This creates a new object-path via the template
'/prefix/sender_id/external_id'. That is, it appends two new labels to
the given prefix. If 'sender_id' is NULL, it will use
bus->unique_name, if 'external_id' is NULL, it will allocate a fresh,
unique cookie from bus->cookie.
bus_path_decode_unique(const char *path,
const char *prefix,
char **ret_sender,
char **ret_external);
This reverses what bus_path_encode_unique() did. It parses 'path' from
the template '/prefix/sender/external' and returns both suffix-labels
in 'ret_sender' and 'ret_external'. In case the template does not
match, 0 is returned and both output arguments are set to NULL.
Otherwise, 1 is returned and the output arguments contain the decoded
labels.
Note: Client-side allocated IDs are inspired by the Wayland protocol
(which itself was inspired by X11). Wayland uses those IDs heavily
to avoid round-trips. Clients can create server-side objects and
send method calls without any round-trip and waiting for any object
IDs to be returned. But unlike Wayland, DBus uses gobally namespaced
object names. Therefore, we have to add the extra step by adding the
unique-name of the bus connection.
2015-04-10 17:44:30 +02:00
|
|
|
/**
|
|
|
|
* bus_path_encode_unique() - encode unique object path
|
|
|
|
* @b: bus connection or NULL
|
|
|
|
* @prefix: object path prefix
|
|
|
|
* @sender_id: unique-name of client, or NULL
|
|
|
|
* @external_id: external ID to be chosen by client, or NULL
|
|
|
|
* @ret_path: storage for encoded object path pointer
|
|
|
|
*
|
|
|
|
* Whenever we provide a bus API that allows clients to create and manage
|
|
|
|
* server-side objects, we need to provide a unique name for these objects. If
|
|
|
|
* we let the server choose the name, we suffer from a race condition: If a
|
|
|
|
* client creates an object asynchronously, it cannot destroy that object until
|
|
|
|
* it received the method reply. It cannot know the name of the new object,
|
|
|
|
* thus, it cannot destroy it. Furthermore, it enforces a round-trip.
|
|
|
|
*
|
|
|
|
* Therefore, many APIs allow the client to choose the unique name for newly
|
|
|
|
* created objects. There're two problems to solve, though:
|
|
|
|
* 1) Object names are usually defined via dbus object paths, which are
|
|
|
|
* usually globally namespaced. Therefore, multiple clients must be able
|
|
|
|
* to choose unique object names without interference.
|
|
|
|
* 2) If multiple libraries share the same bus connection, they must be
|
|
|
|
* able to choose unique object names without interference.
|
|
|
|
* The first problem is solved easily by prefixing a name with the
|
|
|
|
* unique-bus-name of a connection. The server side must enforce this and
|
|
|
|
* reject any other name. The second problem is solved by providing unique
|
|
|
|
* suffixes from within sd-bus.
|
|
|
|
*
|
|
|
|
* This helper allows clients to create unique object-paths. It uses the
|
|
|
|
* template '/prefix/sender_id/external_id' and returns the new path in
|
|
|
|
* @ret_path (must be freed by the caller).
|
|
|
|
* If @sender_id is NULL, the unique-name of @b is used. If @external_id is
|
|
|
|
* NULL, this function allocates a unique suffix via @b (by requesting a new
|
|
|
|
* cookie). If both @sender_id and @external_id are given, @b can be passed as
|
|
|
|
* NULL.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, negative error code on failure.
|
|
|
|
*/
|
|
|
|
int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
|
|
|
|
_cleanup_free_ char *sender_label = NULL, *external_label = NULL;
|
|
|
|
char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(b || (sender_id && external_id), -EINVAL);
|
2020-05-24 13:39:25 +02:00
|
|
|
assert_return(sd_bus_object_path_is_valid(prefix), -EINVAL);
|
bus: implement bus_path_{en,de}code_unique()
Whenever we provide a bus API that allows clients to create and manage
server-side objects, we need to provide a unique name for these objects.
There are two ways to provide them:
1) Let the server choose a name and return it as method reply.
2) Let the client pass its name of choice in the method arguments.
The first method is the easiest one to implement. However, it suffers from
a race condition: If a client creates an object asynchronously, it cannot
destroy that object until it received the method reply. It cannot know the
name of the new object, thus, it cannot destroy it. Furthermore, this
method enforces a round-trip. If the client _depends_ on the method call
to succeed (eg., it would close() the connection if it failed), the client
usually has no reason to wait for the method reply. Instead, the client
can immediately schedule further method calls on the newly created object
(in case the API guarantees in-order method-call handling).
The second method fixes both problems: The client passes an object name
with the method-call. The server uses it to create the object. Therefore,
the client can schedule object destruction even if the object-creation
hasn't finished, yet (again, requiring in-order method-call handling).
Furthermore, the client can schedule further method calls on the newly
created object, before the constructor returned.
There're two problems to solve, though:
1) Object names are usually defined via dbus object paths, which are
usually globally namespaced. Therefore, multiple clients must be able
to choose unique object names without interference.
2) If multiple libraries share the same bus connection, they must be
able to choose unique object names without interference.
The first problem is solved easily by prefixing a name with the
unique-bus-name of a connection. The server side must enforce this and
reject any other name.
The second problem is solved by providing unique suffixes from within
sd-bus. As long as sd-bus always returns a fresh new ID, if requested,
multiple libraries will never interfere. This implementation re-uses
bus->cookie as ID generator, which already provides unique IDs for each
bus connection.
This patch introduces two new helpers:
bus_path_encode_unique(sd_bus *bus,
const char *prefix,
const char *sender_id,
const char *external_id,
char **ret_path);
This creates a new object-path via the template
'/prefix/sender_id/external_id'. That is, it appends two new labels to
the given prefix. If 'sender_id' is NULL, it will use
bus->unique_name, if 'external_id' is NULL, it will allocate a fresh,
unique cookie from bus->cookie.
bus_path_decode_unique(const char *path,
const char *prefix,
char **ret_sender,
char **ret_external);
This reverses what bus_path_encode_unique() did. It parses 'path' from
the template '/prefix/sender/external' and returns both suffix-labels
in 'ret_sender' and 'ret_external'. In case the template does not
match, 0 is returned and both output arguments are set to NULL.
Otherwise, 1 is returned and the output arguments contain the decoded
labels.
Note: Client-side allocated IDs are inspired by the Wayland protocol
(which itself was inspired by X11). Wayland uses those IDs heavily
to avoid round-trips. Clients can create server-side objects and
send method calls without any round-trip and waiting for any object
IDs to be returned. But unlike Wayland, DBus uses gobally namespaced
object names. Therefore, we have to add the extra step by adding the
unique-name of the bus connection.
2015-04-10 17:44:30 +02:00
|
|
|
assert_return(ret_path, -EINVAL);
|
|
|
|
|
|
|
|
if (!sender_id) {
|
|
|
|
r = sd_bus_get_unique_name(b, &sender_id);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!external_id) {
|
|
|
|
xsprintf(external_buf, "%"PRIu64, ++b->cookie);
|
|
|
|
external_id = external_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
sender_label = bus_label_escape(sender_id);
|
|
|
|
if (!sender_label)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
external_label = bus_label_escape(external_id);
|
|
|
|
if (!external_label)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-06-20 20:07:01 +02:00
|
|
|
p = path_join(prefix, sender_label, external_label);
|
bus: implement bus_path_{en,de}code_unique()
Whenever we provide a bus API that allows clients to create and manage
server-side objects, we need to provide a unique name for these objects.
There are two ways to provide them:
1) Let the server choose a name and return it as method reply.
2) Let the client pass its name of choice in the method arguments.
The first method is the easiest one to implement. However, it suffers from
a race condition: If a client creates an object asynchronously, it cannot
destroy that object until it received the method reply. It cannot know the
name of the new object, thus, it cannot destroy it. Furthermore, this
method enforces a round-trip. If the client _depends_ on the method call
to succeed (eg., it would close() the connection if it failed), the client
usually has no reason to wait for the method reply. Instead, the client
can immediately schedule further method calls on the newly created object
(in case the API guarantees in-order method-call handling).
The second method fixes both problems: The client passes an object name
with the method-call. The server uses it to create the object. Therefore,
the client can schedule object destruction even if the object-creation
hasn't finished, yet (again, requiring in-order method-call handling).
Furthermore, the client can schedule further method calls on the newly
created object, before the constructor returned.
There're two problems to solve, though:
1) Object names are usually defined via dbus object paths, which are
usually globally namespaced. Therefore, multiple clients must be able
to choose unique object names without interference.
2) If multiple libraries share the same bus connection, they must be
able to choose unique object names without interference.
The first problem is solved easily by prefixing a name with the
unique-bus-name of a connection. The server side must enforce this and
reject any other name.
The second problem is solved by providing unique suffixes from within
sd-bus. As long as sd-bus always returns a fresh new ID, if requested,
multiple libraries will never interfere. This implementation re-uses
bus->cookie as ID generator, which already provides unique IDs for each
bus connection.
This patch introduces two new helpers:
bus_path_encode_unique(sd_bus *bus,
const char *prefix,
const char *sender_id,
const char *external_id,
char **ret_path);
This creates a new object-path via the template
'/prefix/sender_id/external_id'. That is, it appends two new labels to
the given prefix. If 'sender_id' is NULL, it will use
bus->unique_name, if 'external_id' is NULL, it will allocate a fresh,
unique cookie from bus->cookie.
bus_path_decode_unique(const char *path,
const char *prefix,
char **ret_sender,
char **ret_external);
This reverses what bus_path_encode_unique() did. It parses 'path' from
the template '/prefix/sender/external' and returns both suffix-labels
in 'ret_sender' and 'ret_external'. In case the template does not
match, 0 is returned and both output arguments are set to NULL.
Otherwise, 1 is returned and the output arguments contain the decoded
labels.
Note: Client-side allocated IDs are inspired by the Wayland protocol
(which itself was inspired by X11). Wayland uses those IDs heavily
to avoid round-trips. Clients can create server-side objects and
send method calls without any round-trip and waiting for any object
IDs to be returned. But unlike Wayland, DBus uses gobally namespaced
object names. Therefore, we have to add the extra step by adding the
unique-name of the bus connection.
2015-04-10 17:44:30 +02:00
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*ret_path = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* bus_path_decode_unique() - decode unique object path
|
|
|
|
* @path: object path to decode
|
|
|
|
* @prefix: object path prefix
|
|
|
|
* @ret_sender: output parameter for sender-id label
|
|
|
|
* @ret_external: output parameter for external-id label
|
|
|
|
*
|
|
|
|
* This does the reverse of bus_path_encode_unique() (see its description for
|
|
|
|
* details). Both trailing labels, sender-id and external-id, are unescaped and
|
|
|
|
* returned in the given output parameters (the caller must free them).
|
|
|
|
*
|
|
|
|
* Note that this function returns 0 if the path does not match the template
|
|
|
|
* (see bus_path_encode_unique()), 1 if it matched.
|
|
|
|
*
|
|
|
|
* Returns: Negative error code on failure, 0 if the given object path does not
|
|
|
|
* match the template (return parameters are set to NULL), 1 if it was
|
|
|
|
* parsed successfully (return parameters contain allocated labels).
|
|
|
|
*/
|
|
|
|
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
|
|
|
|
const char *p, *q;
|
|
|
|
char *sender, *external;
|
|
|
|
|
2020-05-24 13:39:25 +02:00
|
|
|
assert(sd_bus_object_path_is_valid(path));
|
|
|
|
assert(sd_bus_object_path_is_valid(prefix));
|
bus: implement bus_path_{en,de}code_unique()
Whenever we provide a bus API that allows clients to create and manage
server-side objects, we need to provide a unique name for these objects.
There are two ways to provide them:
1) Let the server choose a name and return it as method reply.
2) Let the client pass its name of choice in the method arguments.
The first method is the easiest one to implement. However, it suffers from
a race condition: If a client creates an object asynchronously, it cannot
destroy that object until it received the method reply. It cannot know the
name of the new object, thus, it cannot destroy it. Furthermore, this
method enforces a round-trip. If the client _depends_ on the method call
to succeed (eg., it would close() the connection if it failed), the client
usually has no reason to wait for the method reply. Instead, the client
can immediately schedule further method calls on the newly created object
(in case the API guarantees in-order method-call handling).
The second method fixes both problems: The client passes an object name
with the method-call. The server uses it to create the object. Therefore,
the client can schedule object destruction even if the object-creation
hasn't finished, yet (again, requiring in-order method-call handling).
Furthermore, the client can schedule further method calls on the newly
created object, before the constructor returned.
There're two problems to solve, though:
1) Object names are usually defined via dbus object paths, which are
usually globally namespaced. Therefore, multiple clients must be able
to choose unique object names without interference.
2) If multiple libraries share the same bus connection, they must be
able to choose unique object names without interference.
The first problem is solved easily by prefixing a name with the
unique-bus-name of a connection. The server side must enforce this and
reject any other name.
The second problem is solved by providing unique suffixes from within
sd-bus. As long as sd-bus always returns a fresh new ID, if requested,
multiple libraries will never interfere. This implementation re-uses
bus->cookie as ID generator, which already provides unique IDs for each
bus connection.
This patch introduces two new helpers:
bus_path_encode_unique(sd_bus *bus,
const char *prefix,
const char *sender_id,
const char *external_id,
char **ret_path);
This creates a new object-path via the template
'/prefix/sender_id/external_id'. That is, it appends two new labels to
the given prefix. If 'sender_id' is NULL, it will use
bus->unique_name, if 'external_id' is NULL, it will allocate a fresh,
unique cookie from bus->cookie.
bus_path_decode_unique(const char *path,
const char *prefix,
char **ret_sender,
char **ret_external);
This reverses what bus_path_encode_unique() did. It parses 'path' from
the template '/prefix/sender/external' and returns both suffix-labels
in 'ret_sender' and 'ret_external'. In case the template does not
match, 0 is returned and both output arguments are set to NULL.
Otherwise, 1 is returned and the output arguments contain the decoded
labels.
Note: Client-side allocated IDs are inspired by the Wayland protocol
(which itself was inspired by X11). Wayland uses those IDs heavily
to avoid round-trips. Clients can create server-side objects and
send method calls without any round-trip and waiting for any object
IDs to be returned. But unlike Wayland, DBus uses gobally namespaced
object names. Therefore, we have to add the extra step by adding the
unique-name of the bus connection.
2015-04-10 17:44:30 +02:00
|
|
|
assert(ret_sender);
|
|
|
|
assert(ret_external);
|
|
|
|
|
|
|
|
p = object_path_startswith(path, prefix);
|
|
|
|
if (!p) {
|
|
|
|
*ret_sender = NULL;
|
|
|
|
*ret_external = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
q = strchr(p, '/');
|
|
|
|
if (!q) {
|
|
|
|
*ret_sender = NULL;
|
|
|
|
*ret_external = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sender = bus_label_unescape_n(p, q - p);
|
|
|
|
external = bus_label_unescape(q + 1);
|
|
|
|
if (!sender || !external) {
|
|
|
|
free(sender);
|
|
|
|
free(external);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ret_sender = sender;
|
|
|
|
*ret_external = external;
|
|
|
|
return 1;
|
|
|
|
}
|
2015-08-27 16:32:22 +02:00
|
|
|
|
2016-11-15 19:18:36 +01:00
|
|
|
int bus_track_add_name_many(sd_bus_track *t, char **l) {
|
|
|
|
int r = 0;
|
|
|
|
char **i;
|
|
|
|
|
|
|
|
assert(t);
|
|
|
|
|
|
|
|
/* Continues adding after failure, and returns the first failure. */
|
|
|
|
|
|
|
|
STRV_FOREACH(i, l) {
|
|
|
|
int k;
|
|
|
|
|
|
|
|
k = sd_bus_track_add_name(t, *i);
|
|
|
|
if (k < 0 && r >= 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2017-12-19 15:54:30 +01:00
|
|
|
|
2018-04-17 16:37:52 +02:00
|
|
|
int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
|
2019-01-17 16:07:22 +01:00
|
|
|
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
|
2017-12-19 15:54:30 +01:00
|
|
|
const char *e;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
2019-08-27 19:00:50 +02:00
|
|
|
/* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal
|
|
|
|
* turned on. */
|
2017-12-19 15:54:30 +01:00
|
|
|
|
|
|
|
r = sd_bus_new(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-17 16:37:52 +02:00
|
|
|
if (description) {
|
|
|
|
r = sd_bus_set_description(bus, description);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
|
|
|
|
if (!e)
|
|
|
|
e = DEFAULT_SYSTEM_BUS_ADDRESS;
|
|
|
|
|
|
|
|
r = sd_bus_set_address(bus, e);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_set_bus_client(bus, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_set_watch_bind(bus, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_set_connected_signal(bus, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_start(bus);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(bus);
|
2017-12-19 15:54:30 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-05-19 18:55:39 +02:00
|
|
|
|
2018-04-09 19:44:21 +02:00
|
|
|
int bus_reply_pair_array(sd_bus_message *m, char **l) {
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
char **k, **v;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2019-08-27 19:00:50 +02:00
|
|
|
/* Reply to the specified message with a message containing a dictionary put together from the
|
|
|
|
* specified strv */
|
2018-04-09 19:44:21 +02:00
|
|
|
|
|
|
|
r = sd_bus_message_new_method_return(m, &reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(reply, 'a', "{ss}");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
STRV_FOREACH_PAIR(k, v, l) {
|
|
|
|
r = sd_bus_message_append(reply, "{ss}", *k, *v);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return sd_bus_send(NULL, reply, NULL);
|
|
|
|
}
|
logind: add SetBrightness() bus call for setting brightness of leds/backlight devices associated with a seat
This augments the drm/input device management by adding a single method
call for setting the brightness of an "leds" or "backlight" kernel class
device.
This method call requires no privileges to call, but a caller can only
change the brightness on sessions that are currently active, and they
must own the session.
This does not do enumeration of such class devices, feature or range
probing, chnage notification; it doesn't help associating graphics or
input devices with their backlight or leds devices. For all that clients
should go directly to udev/sysfs. The SetBrightness() call is just for
executing the actual change operation, that is otherwise privileged.
Example line:
busctl call org.freedesktop.login1 /org/freedesktop/login1/session/self org.freedesktop.login1.Session SetBrightness ssu "backlight" "intel_backlight" 200
The parameter the SetBrightness() call takes are the kernel subsystem
(i.e. "leds" or "backlight"), the device name, and the brightness
value.
On some hw setting the brightness is slow, and implementation and write
access to the sysfs knobs exposes this slowness. Due to this we'll fork
off a writer process in the background so that logind doesn't have to
block. Moreover, write requestes are coalesced: when a write request is
enqueued while one is already being executed it is queued. When another
write reques is then enqueued the earlier one is replaced by the newer
one, so that only one queued write request per device remains at any
time. Method replies are sent as soon as the first write request that
happens after the request was received is completed.
It is recommended that bus clients turn off the "expect_reply" flag on
the dbus messages they send though, that relieves logind from sending
completion notification and is particularly a good idea if clients
implement reactive UI sliders that send a quick secession of write
requests.
Replaces: #12413
2019-04-28 11:07:56 +02:00
|
|
|
|
|
|
|
static void bus_message_unref_wrapper(void *m) {
|
|
|
|
sd_bus_message_unref(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct hash_ops bus_message_hash_ops = {
|
|
|
|
.hash = trivial_hash_func,
|
|
|
|
.compare = trivial_compare_func,
|
|
|
|
.free_value = bus_message_unref_wrapper,
|
|
|
|
};
|