2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2014-12-10 19:00:46 +01:00
|
|
|
#include "bus-common-errors.h"
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "bus-internal.h"
|
|
|
|
#include "bus-util.h"
|
2015-02-18 17:40:57 +01:00
|
|
|
#include "dbus-cgroup.h"
|
|
|
|
#include "dbus-kill.h"
|
|
|
|
#include "dbus-scope.h"
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "dbus-unit.h"
|
2017-12-29 09:08:22 +01:00
|
|
|
#include "dbus-util.h"
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "dbus.h"
|
|
|
|
#include "scope.h"
|
|
|
|
#include "selinux-access.h"
|
|
|
|
#include "unit.h"
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2018-10-05 22:50:25 +02:00
|
|
|
int bus_scope_method_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2014-02-06 17:17:51 +01:00
|
|
|
Scope *s = userdata;
|
2014-02-07 17:59:27 +01:00
|
|
|
int r;
|
2014-02-06 17:17:51 +01:00
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
2015-02-18 17:40:57 +01:00
|
|
|
r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
|
2014-08-06 11:45:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
|
|
|
|
2014-02-07 17:59:27 +01:00
|
|
|
r = scope_abandon(s);
|
|
|
|
if (r == -ESTALE)
|
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
|
2015-02-18 17:40:57 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-02-07 17:59:27 +01:00
|
|
|
|
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2014-02-06 17:17:51 +01:00
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
const sd_bus_vtable bus_scope_vtable[] = {
|
|
|
|
SD_BUS_VTABLE_START(0),
|
2017-11-23 20:15:48 +01:00
|
|
|
SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
2013-12-22 02:24:05 +01:00
|
|
|
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
2013-11-19 21:12:59 +01:00
|
|
|
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
2019-06-12 09:45:26 +02:00
|
|
|
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Scope, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
2014-01-31 17:45:13 +01:00
|
|
|
SD_BUS_SIGNAL("RequestStop", NULL, 0),
|
2018-10-05 22:50:25 +02:00
|
|
|
SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_method_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
|
2013-11-19 21:12:59 +01:00
|
|
|
SD_BUS_VTABLE_END
|
|
|
|
};
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2013-07-01 00:40:56 +02:00
|
|
|
static int bus_scope_set_transient_property(
|
2013-07-01 00:03:57 +02:00
|
|
|
Scope *s,
|
|
|
|
const char *name,
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_bus_message *message,
|
2017-11-22 15:03:51 +01:00
|
|
|
UnitWriteFlags flags,
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_bus_error *error) {
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2019-06-12 09:44:21 +02:00
|
|
|
Unit *u = UNIT(s);
|
2013-07-01 00:03:57 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(name);
|
|
|
|
assert(message);
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2017-11-22 15:03:51 +01:00
|
|
|
flags |= UNIT_PRIVATE;
|
|
|
|
|
2017-12-29 09:08:22 +01:00
|
|
|
if (streq(name, "TimeoutStopUSec"))
|
2019-06-12 09:44:21 +02:00
|
|
|
return bus_set_transient_usec(u, name, &s->timeout_stop_usec, message, flags, error);
|
2017-12-29 09:08:22 +01:00
|
|
|
|
2019-06-12 09:45:26 +02:00
|
|
|
if (streq(name, "RuntimeMaxUSec"))
|
|
|
|
return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
if (streq(name, "PIDs")) {
|
2018-02-07 22:52:52 +01:00
|
|
|
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
2013-07-02 16:44:02 +02:00
|
|
|
unsigned n = 0;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
r = sd_bus_message_enter_container(message, 'a', "u");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2018-02-07 22:52:52 +01:00
|
|
|
for (;;) {
|
|
|
|
uint32_t upid;
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
r = sd_bus_message_read(message, "u", &upid);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (upid == 0) {
|
|
|
|
if (!creds) {
|
|
|
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_creds_get_pid(creds, &pid);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else
|
|
|
|
pid = (uid_t) upid;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2019-06-12 09:44:21 +02:00
|
|
|
r = unit_pid_attachable(u, pid, error);
|
2018-02-07 22:52:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2017-11-22 15:03:51 +01:00
|
|
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
2019-06-12 09:44:21 +02:00
|
|
|
r = unit_watch_pid(u, pid, false);
|
2013-07-01 02:47:11 +02:00
|
|
|
if (r < 0 && r != -EEXIST)
|
|
|
|
return r;
|
|
|
|
}
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2013-07-01 02:47:11 +02:00
|
|
|
n++;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
2013-11-19 21:12:59 +01:00
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(message);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2013-07-01 02:47:11 +02:00
|
|
|
if (n <= 0)
|
2013-07-01 00:03:57 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 1;
|
2013-07-02 01:34:04 +02:00
|
|
|
|
2014-01-31 17:45:13 +01:00
|
|
|
} else if (streq(name, "Controller")) {
|
|
|
|
const char *controller;
|
|
|
|
|
2017-11-23 20:02:00 +01:00
|
|
|
/* We can't support direct connections with this, as direct connections know no service or unique name
|
|
|
|
* concept, but the Controller field stores exactly that. */
|
2019-06-12 09:44:21 +02:00
|
|
|
if (sd_bus_message_get_bus(message) != u->manager->api_bus)
|
2017-11-23 20:02:00 +01:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Sorry, Controller= logic only supported via the bus.");
|
|
|
|
|
2014-01-31 17:45:13 +01:00
|
|
|
r = sd_bus_message_read(message, "s", &controller);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!isempty(controller) && !service_name_is_valid(controller))
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
|
|
|
|
|
2017-11-22 15:03:51 +01:00
|
|
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
|
|
|
r = free_and_strdup(&s->controller, empty_to_null(controller));
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-31 17:45:13 +01:00
|
|
|
}
|
|
|
|
|
2013-07-02 01:34:04 +02:00
|
|
|
return 1;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bus_scope_set_property(
|
|
|
|
Unit *u,
|
|
|
|
const char *name,
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_bus_message *message,
|
2017-11-22 15:03:51 +01:00
|
|
|
UnitWriteFlags flags,
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_bus_error *error) {
|
2013-07-01 00:03:57 +02:00
|
|
|
|
|
|
|
Scope *s = SCOPE(u);
|
|
|
|
int r;
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(s);
|
2013-07-01 00:03:57 +02:00
|
|
|
assert(name);
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(message);
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2017-11-22 15:03:51 +01:00
|
|
|
r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
|
2013-07-01 00:03:57 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (u->load_state == UNIT_STUB) {
|
|
|
|
/* While we are created we still accept PIDs */
|
|
|
|
|
2017-11-22 15:03:51 +01:00
|
|
|
r = bus_scope_set_transient_property(s, name, message, flags, error);
|
2013-07-01 00:03:57 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
2013-07-30 02:28:22 +02:00
|
|
|
|
2017-11-22 15:03:51 +01:00
|
|
|
r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
|
2013-07-30 02:28:22 +02:00
|
|
|
if (r != 0)
|
|
|
|
return r;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bus_scope_commit_properties(Unit *u) {
|
|
|
|
assert(u);
|
|
|
|
|
cgroup: drastically simplify caching of cgroups members mask
Previously we tried to be smart: when a new unit appeared and it only
added controllers to the cgroup mask we'd update the cached members mask
in all parents by ORing in the controller flags in their cached values.
Unfortunately this was quite broken, as we missed some conditions when
this cache had to be reset (for example, when a unit got unloaded),
moreover the optimization doesn't work when a controller is removed
anyway (as in that case there's no other way for the parent to iterate
though all children if any other, remaining child unit still needs it).
Hence, let's simplify the logic substantially: instead of updating the
cache on the right events (which we didn't get right), let's simply
invalidate the cache, and generate it lazily when we encounter it later.
This should actually result in better behaviour as we don't have to
calculate the new members mask for a whole subtree whever we have the
suspicion something changed, but can delay it to the point where we
actually need the members mask.
This allows us to simplify things quite a bit, which is good, since
validating this cache for correctness is hard enough.
Fixes: #9512
2018-11-23 01:07:34 +01:00
|
|
|
unit_invalidate_cgroup_members_masks(u);
|
2013-07-01 00:03:57 +02:00
|
|
|
unit_realize_cgroup(u);
|
2014-02-14 19:11:07 +01:00
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2014-01-31 17:45:13 +01:00
|
|
|
|
|
|
|
int bus_scope_send_request_stop(Scope *s) {
|
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 *m = NULL;
|
2014-01-31 17:45:13 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!s->controller)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
p = unit_dbus_path(UNIT(s));
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = sd_bus_message_new_signal(
|
|
|
|
UNIT(s)->manager->api_bus,
|
2014-02-19 23:54:58 +01:00
|
|
|
&m,
|
2014-01-31 17:45:13 +01:00
|
|
|
p,
|
|
|
|
"org.freedesktop.systemd1.Scope",
|
2014-02-19 23:54:58 +01:00
|
|
|
"RequestStop");
|
2014-01-31 17:45:13 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-07-20 13:39:23 +02:00
|
|
|
return sd_bus_send_to(UNIT(s)->manager->api_bus, m, s->controller, NULL);
|
2014-01-31 17:45:13 +01:00
|
|
|
}
|
2017-11-23 20:15:48 +01:00
|
|
|
|
|
|
|
static int on_controller_gone(sd_bus_track *track, void *userdata) {
|
|
|
|
Scope *s = userdata;
|
|
|
|
|
|
|
|
assert(track);
|
|
|
|
|
|
|
|
if (s->controller) {
|
|
|
|
log_unit_debug(UNIT(s), "Controller %s disappeared from bus.", s->controller);
|
|
|
|
unit_add_to_dbus_queue(UNIT(s));
|
|
|
|
s->controller = mfree(s->controller);
|
|
|
|
}
|
|
|
|
|
|
|
|
s->controller_track = sd_bus_track_unref(s->controller_track);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bus_scope_track_controller(Scope *s) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (!s->controller || s->controller_track)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_bus_track_new(UNIT(s)->manager->api_bus, &s->controller_track, on_controller_gone, s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_track_add_name(s->controller_track, s->controller);
|
|
|
|
if (r < 0) {
|
|
|
|
s->controller_track = sd_bus_track_unref(s->controller_track);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|