blob: ca9b399d8c91b0de1d8b6c8ee26f560d8baeb34a [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-polkit.h"
#include "bus-util.h"
#include "dbus-util.h"
#include "escape.h"
#include "parse-util.h"
#include "path-util.h"
#include "unit-printf.h"
#include "user-util.h"
#include "unit.h"
int bus_property_get_triggered_unit(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Unit *u = userdata, *trigger;
assert(bus);
assert(reply);
assert(u);
trigger = UNIT_TRIGGER(u);
return sd_bus_message_append(reply, "s", trigger ? trigger->id : NULL);
}
BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
static inline bool valid_user_group_name_or_id_relaxed(const char *u) {
return valid_user_group_name(u, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX);
}
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_relaxed, valid_user_group_name_or_id_relaxed);
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute);
int bus_set_transient_string(
Unit *u,
const char *name,
char **p,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
const char *v;
int r;
assert(p);
r = sd_bus_message_read(message, "s", &v);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = free_and_strdup(p, empty_to_null(v));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
"%s=%s", name, strempty(v));
}
return 1;
}
int bus_set_transient_bool(
Unit *u,
const char *name,
bool *p,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
int v, r;
assert(p);
r = sd_bus_message_read(message, "b", &v);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
*p = v;
unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(v));
}
return 1;
}
int bus_set_transient_usec_internal(
Unit *u,
const char *name,
usec_t *p,
bool fix_0,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
uint64_t v;
int r;
assert(p);
r = sd_bus_message_read(message, "t", &v);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
char *n, ts[FORMAT_TIMESPAN_MAX];
if (fix_0)
*p = v != 0 ? v: USEC_INFINITY;
else
*p = v;
n = strndupa(name, strlen(name) - 4);
unit_write_settingf(u, flags, name, "%sSec=%s", n,
format_timespan(ts, sizeof(ts), v, USEC_PER_MSEC));
}
return 1;
}
int bus_verify_manage_units_async_full(
Unit *u,
const char *verb,
int capability,
const char *polkit_message,
bool interactive,
sd_bus_message *call,
sd_bus_error *error) {
const char *details[9] = {
"unit", u->id,
"verb", verb,
};
if (polkit_message) {
details[4] = "polkit.message";
details[5] = polkit_message;
details[6] = "polkit.gettext_domain";
details[7] = GETTEXT_PACKAGE;
}
return bus_verify_polkit_async(
call,
capability,
"org.freedesktop.systemd1.manage-units",
details,
interactive,
UID_INVALID,
&u->manager->polkit_registry,
error);
}
/* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */
int bus_read_mount_options(
sd_bus_message *message,
sd_bus_error *error,
MountOptions **ret_options,
char **ret_format_str,
const char *separator) {
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
_cleanup_free_ char *format_str = NULL;
const char *mount_options, *partition;
int r;
assert(message);
assert(ret_options);
assert(separator);
r = sd_bus_message_enter_container(message, 'a', "(ss)");
if (r < 0)
return r;
while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
_cleanup_free_ char *escaped = NULL;
_cleanup_free_ MountOptions *o = NULL;
PartitionDesignator partition_designator;
if (chars_intersect(mount_options, WHITESPACE))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid mount options string, contains whitespace character(s): %s", mount_options);
partition_designator = partition_designator_from_string(partition);
if (partition_designator < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition);
/* Need to store the options with the escapes, so that they can be parsed again */
escaped = shell_escape(mount_options, ":");
if (!escaped)
return -ENOMEM;
if (!strextend_with_separator(&format_str, separator, partition, ":", escaped))
return -ENOMEM;
o = new(MountOptions, 1);
if (!o)
return -ENOMEM;
*o = (MountOptions) {
.partition_designator = partition_designator,
.options = strdup(mount_options),
};
if (!o->options)
return -ENOMEM;
LIST_APPEND(mount_options, options, TAKE_PTR(o));
}
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!LIST_IS_EMPTY(options)) {
if (ret_format_str) {
char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str);
if (!final)
return -ENOMEM;
free_and_replace(*ret_format_str, final);
}
LIST_JOIN(mount_options, *ret_options, options);
}
return 0;
}