summaryrefslogtreecommitdiffstats
path: root/src/systemctl/systemctl-set-environment.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemctl/systemctl-set-environment.c')
-rw-r--r--src/systemctl/systemctl-set-environment.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/systemctl/systemctl-set-environment.c b/src/systemctl/systemctl-set-environment.c
new file mode 100644
index 0000000..55d1160
--- /dev/null
+++ b/src/systemctl/systemctl-set-environment.c
@@ -0,0 +1,225 @@
+/* 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;
+}