blob: 55d1160510f6a93ff406d497d85254de74c153c2 [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-error.h"
#include "bus-locator.h"
#include "env-util.h"
#include "escape.h"
#include "systemctl-set-environment.h"
#include "systemctl-util.h"
#include "systemctl.h"
static int json_transform_message(sd_bus_message *m, JsonVariant **ret) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
const char *text;
int r;
assert(m);
assert(ret);
while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &text)) > 0) {
_cleanup_free_ char *n = NULL;
const char *sep;
sep = strchr(text, '=');
if (!sep)
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Invalid environment block");
n = strndup(text, sep - text);
if (!n)
return log_oom();
sep++;
r = json_variant_set_field_string(&v, n, sep);
if (r < 0)
return log_error_errno(r, "Failed to set JSON field '%s' to '%s': %m", n, sep);
}
if (r < 0)
return bus_log_parse_error(r);
*ret = TAKE_PTR(v);
return 0;
}
static int print_variable(const char *s) {
const char *sep;
_cleanup_free_ char *esc = NULL;
sep = strchr(s, '=');
if (!sep)
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Invalid environment block");
esc = shell_maybe_quote(sep + 1, SHELL_ESCAPE_POSIX);
if (!esc)
return log_oom();
printf("%.*s=%s\n", (int)(sep-s), s, esc);
return 0;
}
int verb_show_environment(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *text;
sd_bus *bus;
int r;
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
pager_open(arg_pager_flags);
r = bus_get_property(bus, bus_systemd_mgr, "Environment", &error, &reply, "as");
if (r < 0)
return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
if (r < 0)
return bus_log_parse_error(r);
if (OUTPUT_MODE_IS_JSON(arg_output)) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
r = json_transform_message(reply, &v);
if (r < 0)
return r;
json_variant_dump(v, output_mode_to_json_format_flags(arg_output), stdout, NULL);
} else {
while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
r = print_variable(text);
if (r < 0)
return r;
}
if (r < 0)
return bus_log_parse_error(r);
}
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
return 0;
}
static void invalid_callback(const char *p, void *userdata) {
_cleanup_free_ char *t = cescape(p);
log_debug("Ignoring invalid environment assignment \"%s\".", strnull(t));
}
int verb_set_environment(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
const char *method;
sd_bus *bus;
int r;
assert(argc > 1);
assert(argv);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
polkit_agent_open_maybe();
method = streq(argv[0], "set-environment")
? "SetEnvironment"
: "UnsetEnvironment";
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
if (r < 0)
return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
return 0;
}
int verb_import_environment(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
sd_bus *bus;
int r;
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
polkit_agent_open_maybe();
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetEnvironment");
if (r < 0)
return bus_log_create_error(r);
if (argc < 2) {
log_warning("Calling import-environment without a list of variable names is deprecated.");
_cleanup_strv_free_ char **copy = strv_copy(environ);
if (!copy)
return log_oom();
strv_env_clean_with_callback(copy, invalid_callback, NULL);
STRV_FOREACH(e, copy)
if (string_has_cc(*e, NULL))
log_notice("Environment variable $%.*s contains control characters, importing anyway.",
(int) strcspn(*e, "="), *e);
r = sd_bus_message_append_strv(m, copy);
} else {
r = sd_bus_message_open_container(m, 'a', "s");
if (r < 0)
return bus_log_create_error(r);
STRV_FOREACH(a, strv_skip(argv, 1)) {
if (!env_name_is_valid(*a))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Not a valid environment variable name: %s", *a);
bool found = false;
STRV_FOREACH(b, environ) {
const char *eq;
eq = startswith(*b, *a);
if (eq && *eq == '=') {
if (string_has_cc(eq + 1, NULL))
log_notice("Environment variable $%.*s contains control characters, importing anyway.",
(int) (eq - *b), *b);
r = sd_bus_message_append(m, "s", *b);
if (r < 0)
return bus_log_create_error(r);
found = true;
break;
}
}
if (!found)
log_notice("Environment variable $%s not set, ignoring.", *a);
}
r = sd_bus_message_close_container(m);
}
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
if (r < 0)
return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
return 0;
}