1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "bus-error.h"
4 #include "bus-locator.h"
5 #include "env-util.h"
6 #include "escape.h"
7 #include "systemctl-set-environment.h"
8 #include "systemctl-util.h"
9 #include "systemctl.h"
10
json_transform_message(sd_bus_message * m,JsonVariant ** ret)11 static int json_transform_message(sd_bus_message *m, JsonVariant **ret) {
12 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
13 const char *text;
14 int r;
15
16 assert(m);
17 assert(ret);
18
19 while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &text)) > 0) {
20 _cleanup_free_ char *n = NULL;
21 const char *sep;
22
23 sep = strchr(text, '=');
24 if (!sep)
25 return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
26 "Invalid environment block");
27
28 n = strndup(text, sep - text);
29 if (!n)
30 return log_oom();
31
32 sep++;
33
34 r = json_variant_set_field_string(&v, n, sep);
35 if (r < 0)
36 return log_error_errno(r, "Failed to set JSON field '%s' to '%s': %m", n, sep);
37 }
38 if (r < 0)
39 return bus_log_parse_error(r);
40
41 *ret = TAKE_PTR(v);
42 return 0;
43 }
44
print_variable(const char * s)45 static int print_variable(const char *s) {
46 const char *sep;
47 _cleanup_free_ char *esc = NULL;
48
49 sep = strchr(s, '=');
50 if (!sep)
51 return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
52 "Invalid environment block");
53
54 esc = shell_maybe_quote(sep + 1, SHELL_ESCAPE_POSIX);
55 if (!esc)
56 return log_oom();
57
58 printf("%.*s=%s\n", (int)(sep-s), s, esc);
59 return 0;
60 }
61
verb_show_environment(int argc,char * argv[],void * userdata)62 int verb_show_environment(int argc, char *argv[], void *userdata) {
63 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
64 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
65 const char *text;
66 sd_bus *bus;
67 int r;
68
69 r = acquire_bus(BUS_MANAGER, &bus);
70 if (r < 0)
71 return r;
72
73 pager_open(arg_pager_flags);
74
75 r = bus_get_property(bus, bus_systemd_mgr, "Environment", &error, &reply, "as");
76 if (r < 0)
77 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
78
79 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
80 if (r < 0)
81 return bus_log_parse_error(r);
82
83 if (OUTPUT_MODE_IS_JSON(arg_output)) {
84 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
85
86 r = json_transform_message(reply, &v);
87 if (r < 0)
88 return r;
89
90 json_variant_dump(v, output_mode_to_json_format_flags(arg_output), stdout, NULL);
91 } else {
92 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
93 r = print_variable(text);
94 if (r < 0)
95 return r;
96 }
97 if (r < 0)
98 return bus_log_parse_error(r);
99 }
100
101 r = sd_bus_message_exit_container(reply);
102 if (r < 0)
103 return bus_log_parse_error(r);
104
105 return 0;
106 }
107
invalid_callback(const char * p,void * userdata)108 static void invalid_callback(const char *p, void *userdata) {
109 _cleanup_free_ char *t = cescape(p);
110
111 log_debug("Ignoring invalid environment assignment \"%s\".", strnull(t));
112 }
113
verb_set_environment(int argc,char * argv[],void * userdata)114 int verb_set_environment(int argc, char *argv[], void *userdata) {
115 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
116 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
117 const char *method;
118 sd_bus *bus;
119 int r;
120
121 assert(argc > 1);
122 assert(argv);
123
124 r = acquire_bus(BUS_MANAGER, &bus);
125 if (r < 0)
126 return r;
127
128 polkit_agent_open_maybe();
129
130 method = streq(argv[0], "set-environment")
131 ? "SetEnvironment"
132 : "UnsetEnvironment";
133
134 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
135 if (r < 0)
136 return bus_log_create_error(r);
137
138 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
139 if (r < 0)
140 return bus_log_create_error(r);
141
142 r = sd_bus_call(bus, m, 0, &error, NULL);
143 if (r < 0)
144 return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
145
146 return 0;
147 }
148
verb_import_environment(int argc,char * argv[],void * userdata)149 int verb_import_environment(int argc, char *argv[], void *userdata) {
150 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
151 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
152 sd_bus *bus;
153 int r;
154
155 r = acquire_bus(BUS_MANAGER, &bus);
156 if (r < 0)
157 return r;
158
159 polkit_agent_open_maybe();
160
161 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetEnvironment");
162 if (r < 0)
163 return bus_log_create_error(r);
164
165 if (argc < 2) {
166 log_warning("Calling import-environment without a list of variable names is deprecated.");
167
168 _cleanup_strv_free_ char **copy = strv_copy(environ);
169 if (!copy)
170 return log_oom();
171
172 strv_env_clean_with_callback(copy, invalid_callback, NULL);
173
174 STRV_FOREACH(e, copy)
175 if (string_has_cc(*e, NULL))
176 log_notice("Environment variable $%.*s contains control characters, importing anyway.",
177 (int) strcspn(*e, "="), *e);
178
179 r = sd_bus_message_append_strv(m, copy);
180
181 } else {
182 r = sd_bus_message_open_container(m, 'a', "s");
183 if (r < 0)
184 return bus_log_create_error(r);
185
186 STRV_FOREACH(a, strv_skip(argv, 1)) {
187
188 if (!env_name_is_valid(*a))
189 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
190 "Not a valid environment variable name: %s", *a);
191
192 bool found = false;
193 STRV_FOREACH(b, environ) {
194 const char *eq;
195
196 eq = startswith(*b, *a);
197 if (eq && *eq == '=') {
198 if (string_has_cc(eq + 1, NULL))
199 log_notice("Environment variable $%.*s contains control characters, importing anyway.",
200 (int) (eq - *b), *b);
201
202 r = sd_bus_message_append(m, "s", *b);
203 if (r < 0)
204 return bus_log_create_error(r);
205
206 found = true;
207 break;
208 }
209 }
210
211 if (!found)
212 log_notice("Environment variable $%s not set, ignoring.", *a);
213 }
214
215 r = sd_bus_message_close_container(m);
216 }
217 if (r < 0)
218 return bus_log_create_error(r);
219
220 r = sd_bus_call(bus, m, 0, &error, NULL);
221 if (r < 0)
222 return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
223
224 return 0;
225 }
226