#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-log-control-api.h"
+#include "bus-util.h"
#include "chase.h"
#include "confidential-virt.h"
#include "data-fd-util.h"
* its sleeve: if the name is specified empty we use the client's unit. */
if (isempty(name)) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- pid_t pid;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+ r = bus_query_sender_pidref(message, &pidref);
if (r < 0)
return r;
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
-
- u = manager_get_unit_by_pid(m, pid);
+ u = manager_get_unit_by_pidref(m, &pidref);
if (!u)
return sd_bus_error_set(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
} else {
static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
- pid_t pid;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
Unit *u;
int r;
/* Anyone can call this method */
- r = sd_bus_message_read(message, "u", &pid);
+ r = sd_bus_message_read(message, "u", &pidref.pid);
if (r < 0)
return r;
- if (pid < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pid);
-
- if (pid == 0) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
-
- 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 (pidref.pid < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pidref.pid);
+ if (pidref.pid == 0) {
+ r = bus_query_sender_pidref(message, &pidref);
if (r < 0)
return r;
}
- u = manager_get_unit_by_pid(m, pid);
+ u = manager_get_unit_by_pidref(m, &pidref);
if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pid);
+ return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pidref.pid);
return reply_unit_path(u, message, error);
}
_cleanup_free_ char *path = NULL;
Manager *m = ASSERT_PTR(userdata);
sd_id128_t id;
- const void *a;
Unit *u;
- size_t sz;
int r;
assert(message);
/* Anyone can call this method */
- r = sd_bus_message_read_array(message, 'y', &a, &sz);
- if (r < 0)
- return r;
- if (sz == 0)
- id = SD_ID128_NULL;
- else if (sz == 16)
- memcpy(&id, a, sz);
- else
+ if (bus_message_read_id128(message, &id) < 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid invocation ID");
if (sd_id128_is_null(id)) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- pid_t pid;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+ r = bus_query_sender_pidref(message, &pidref);
if (r < 0)
return r;
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
-
- u = manager_get_unit_by_pid(m, pid);
+ u = manager_get_unit_by_pidref(m, &pidref);
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
- "Client " PID_FMT " not member of any unit.", pid);
+ "Client " PID_FMT " not member of any unit.", pidref.pid);
} else {
u = hashmap_get(m->units_by_invocation_id, &id);
if (!u)
assert(message);
assert(m);
+ assert(handler);
/* Read the first argument from the command and pass the operation to the specified per-unit
* method. */
}
static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- /* Don't load a unit (since it won't have any processes if it's not loaded), but don't insist on the
- * unit being loaded (because even improperly loaded units might still have processes around */
- return method_generic_unit_operation(message, userdata, error, bus_unit_method_get_processes, 0);
+ /* Don't load a unit actively (since it won't have any processes if it's not loaded), but don't
+ * insist on the unit being loaded either (because even improperly loaded units might still have
+ * processes around). */
+ return method_generic_unit_operation(message, userdata, error, bus_unit_method_get_processes, /* flags = */ 0);
}
static int method_attach_processes_to_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
static int reply_dump_by_fd(sd_bus_message *message, char *dump) {
_cleanup_close_ int fd = -EBADF;
- fd = acquire_data_fd(dump, strlen(dump), 0);
+ fd = acquire_data_fd(dump);
if (fd < 0)
return fd;
log_caller(message, m, "Reloading");
/* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
- if (!ratelimit_below(&m->reload_ratelimit)) {
+ if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
log_warning("Reloading request rejected due to rate limit.");
return sd_bus_error_setf(error,
SD_BUS_ERROR_LIMITS_EXCEEDED,
/* Write a log message noting the unit or process who requested the Reexecute() */
log_caller(message, m, "Reexecuting");
+ /* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
+ if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
+ log_warning("Reexecuting request rejected due to rate limit.");
+ return sd_bus_error_setf(error,
+ SD_BUS_ERROR_LIMITS_EXCEEDED,
+ "Reexecute() request rejected due to rate limit.");
+ }
+
/* We don't send a reply back here, the client should
* just wait for us disconnecting. */
return sd_bus_send(bus, message, NULL);
}
-/* Create an error reply, using the error information from changes[]
- * if possible, and fall back to generating an error from error code c.
- * The error message only describes the first error.
- */
static int install_error(
sd_bus_error *error,
int c,
InstallChange *changes,
size_t n_changes) {
- CLEANUP_ARRAY(changes, n_changes, install_changes_free);
+ int r;
- for (size_t i = 0; i < n_changes; i++)
+ /* Create an error reply, using the error information from changes[] if possible, and fall back to
+ * generating an error from error code c. The error message only describes the first error. */
- /* When making changes here, make sure to also change install_changes_dump() in install.c. */
+ assert(changes || n_changes == 0);
- switch (changes[i].type) {
- case 0 ... _INSTALL_CHANGE_TYPE_MAX: /* not errors */
- break;
+ CLEANUP_ARRAY(changes, n_changes, install_changes_free);
- case -EEXIST:
- if (changes[i].source)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
- "File %s already exists and is a symlink to %s.",
- changes[i].path, changes[i].source);
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
- "File %s already exists.",
- changes[i].path);
-
- case -ERFKILL:
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED,
- "Unit file %s is masked.", changes[i].path);
-
- case -EADDRNOTAVAIL:
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED,
- "Unit %s is transient or generated.", changes[i].path);
-
- case -ETXTBSY:
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_BAD_PATH,
- "File %s is under the systemd unit hierarchy already.", changes[i].path);
-
- case -EBADSLT:
- return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
- "Invalid specifier in %s.", changes[i].path);
-
- case -EIDRM:
- return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
- "Destination unit %s is a non-template unit.", changes[i].path);
-
- case -EUCLEAN:
- return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
- "\"%s\" is not a valid unit name.",
- changes[i].path);
-
- case -ELOOP:
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED,
- "Refusing to operate on alias name or linked unit file: %s",
- changes[i].path);
-
- case -EXDEV:
- if (changes[i].source)
- return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
- "Cannot alias %s as %s.",
- changes[i].source, changes[i].path);
- return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
- "Invalid unit reference %s.", changes[i].path);
-
- case -ENOENT:
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
- "Unit file %s does not exist.", changes[i].path);
+ FOREACH_ARRAY(i, changes, n_changes) {
+ _cleanup_free_ char *err_message = NULL;
+ const char *bus_error;
- case -EUNATCH:
- return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
- "Cannot resolve specifiers in %s.", changes[i].path);
+ if (i->type >= 0)
+ continue;
- default:
- assert(changes[i].type < 0); /* other errors */
- return sd_bus_error_set_errnof(error, changes[i].type, "File %s: %m", changes[i].path);
- }
+ r = install_change_dump_error(i, &err_message, &bus_error);
+ if (r == -ENOMEM)
+ return r;
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "File %s: %m", i->path);
+
+ return sd_bus_error_set(error, bus_error, err_message);
+ }
return c < 0 ? c : -EINVAL;
}
if (r < 0)
return r;
- for (size_t i = 0; i < n_changes; i++) {
-
- if (changes[i].type < 0) {
+ FOREACH_ARRAY(i, changes, n_changes) {
+ if (i->type < 0) {
bad = true;
continue;
}
r = sd_bus_message_append(
reply, "(sss)",
- install_change_type_to_string(changes[i].type),
- changes[i].path,
- changes[i].source);
+ install_change_type_to_string(i->type),
+ i->path,
+ i->source);
if (r < 0)
return r;
}
static int aux_scope_from_message(Manager *m, sd_bus_message *message, Unit **ret_scope, sd_bus_error *error) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ _cleanup_(pidref_done) PidRef sender_pidref = PIDREF_NULL;
_cleanup_free_ PidRef *pidrefs = NULL;
const char *name;
Unit *from, *scope;
CGroupContext *cc;
size_t n_pids = 0;
uint64_t flags;
- pid_t pid;
int r;
assert(ret_scope);
- 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);
+ r = bus_query_sender_pidref(message, &sender_pidref);
if (r < 0)
return r;
- from = manager_get_unit_by_pid(m, pid);
+ from = manager_get_unit_by_pidref(m, &sender_pidref);
if (!from)
return sd_bus_error_set(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
BUS_PROPERTY_DUAL_TIMESTAMP("InitRDTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("UserspaceTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_USERSPACE]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("FinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("ShutdownStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_SHUTDOWN_START]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("SecurityStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_SECURITY_START]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("SecurityFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_SECURITY_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_GENERATORS_START]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultOOMPolicy", "s", bus_property_get_oom_policy, offsetof(Manager, defaults.oom_policy), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultOOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CtrlAltDelBurstAction", "s", bus_property_get_emergency_action, offsetof(Manager, cad_burst_action), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SoftRebootsCount", "u", bus_property_get_unsigned, offsetof(Manager, soft_reboots_count), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD_WITH_ARGS("GetUnit",
SD_BUS_ARGS("s", name),