/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- 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 "alloc-util.h"
#include "bus-common-errors.h"
#include "dbus-kill.h"
#include "dbus-scope.h"
#include "dbus-unit.h"
+#include "dbus-util.h"
#include "dbus.h"
#include "scope.h"
#include "selinux-access.h"
#include "unit.h"
-static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_scope_method_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Scope *s = userdata;
int r;
const sd_bus_vtable bus_scope_vtable[] = {
SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_SIGNAL("RequestStop", NULL, 0),
- SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_method_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
Scope *s,
const char *name,
sd_bus_message *message,
- UnitSetPropertiesMode mode,
+ UnitWriteFlags flags,
sd_bus_error *error) {
int r;
assert(name);
assert(message);
+ flags |= UNIT_PRIVATE;
+
+ if (streq(name, "TimeoutStopUSec"))
+ return bus_set_transient_usec(UNIT(s), name, &s->timeout_stop_usec, message, flags, error);
+
if (streq(name, "PIDs")) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
unsigned n = 0;
- uint32_t pid;
r = sd_bus_message_enter_container(message, 'a', "u");
if (r < 0)
return r;
- while ((r = sd_bus_message_read(message, "u", &pid)) > 0) {
+ for (;;) {
+ uint32_t upid;
+ pid_t pid;
- if (pid <= 1)
- return -EINVAL;
+ 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;
+
+ r = unit_pid_attachable(UNIT(s), pid, error);
+ if (r < 0)
+ return r;
- if (mode != UNIT_CHECK) {
- r = unit_watch_pid(UNIT(s), pid);
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ r = unit_watch_pid(UNIT(s), pid, false);
if (r < 0 && r != -EEXIST)
return r;
}
n++;
}
- if (r < 0)
- return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
} else if (streq(name, "Controller")) {
const char *controller;
- char *c;
+
+ /* 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. */
+ if (sd_bus_message_get_bus(message) != UNIT(s)->manager->api_bus)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Sorry, Controller= logic only supported via the bus.");
r = sd_bus_message_read(message, "s", &controller);
if (r < 0)
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);
- if (mode != UNIT_CHECK) {
- if (isempty(controller))
- c = NULL;
- else {
- c = strdup(controller);
- if (!c)
- return -ENOMEM;
- }
-
- free(s->controller);
- s->controller = c;
- }
-
- return 1;
-
- } else if (streq(name, "TimeoutStopUSec")) {
-
- if (mode != UNIT_CHECK) {
- r = sd_bus_message_read(message, "t", &s->timeout_stop_usec);
- if (r < 0)
- return r;
-
- unit_write_drop_in_private_format(UNIT(s), mode, name, "TimeoutStopSec="USEC_FMT"us", s->timeout_stop_usec);
- } else {
- r = sd_bus_message_skip(message, "t");
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ r = free_and_strdup(&s->controller, empty_to_null(controller));
if (r < 0)
return r;
}
Unit *u,
const char *name,
sd_bus_message *message,
- UnitSetPropertiesMode mode,
+ UnitWriteFlags flags,
sd_bus_error *error) {
Scope *s = SCOPE(u);
assert(name);
assert(message);
- r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
+ r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
if (r != 0)
return r;
if (u->load_state == UNIT_STUB) {
/* While we are created we still accept PIDs */
- r = bus_scope_set_transient_property(s, name, message, mode, error);
+ r = bus_scope_set_transient_property(s, name, message, flags, error);
if (r != 0)
return r;
- r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
+ r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
if (r != 0)
return r;
}
int bus_scope_commit_properties(Unit *u) {
assert(u);
- unit_update_cgroup_members_masks(u);
+ unit_invalidate_cgroup_members_masks(u);
unit_realize_cgroup(u);
return 0;
return sd_bus_send_to(UNIT(s)->manager->api_bus, m, s->controller, NULL);
}
+
+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;
+}