]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
daf71ef6 LP |
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 | ||
5ef599b3 JH |
11 | static int json_transform_message(sd_bus_message *m, JsonVariant **ret) { |
12 | _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; | |
92b29166 | 13 | const char *text; |
5ef599b3 JH |
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) { | |
92b29166 LP |
20 | _cleanup_free_ char *n = NULL; |
21 | const char *sep; | |
5ef599b3 | 22 | |
92b29166 | 23 | sep = strchr(text, '='); |
5ef599b3 JH |
24 | if (!sep) |
25 | return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), | |
26 | "Invalid environment block"); | |
27 | ||
92b29166 LP |
28 | n = strndup(text, sep - text); |
29 | if (!n) | |
30 | return log_oom(); | |
5ef599b3 | 31 | |
92b29166 | 32 | sep++; |
5ef599b3 | 33 | |
92b29166 | 34 | r = json_variant_set_field_string(&v, n, sep); |
5ef599b3 | 35 | if (r < 0) |
92b29166 | 36 | return log_error_errno(r, "Failed to set JSON field '%s' to '%s': %m", n, sep); |
5ef599b3 JH |
37 | } |
38 | if (r < 0) | |
39 | return bus_log_parse_error(r); | |
40 | ||
41 | *ret = TAKE_PTR(v); | |
92b29166 | 42 | return 0; |
5ef599b3 JH |
43 | } |
44 | ||
daf71ef6 LP |
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 | ||
9e53c10a | 54 | esc = shell_maybe_quote(sep + 1, SHELL_ESCAPE_POSIX); |
daf71ef6 LP |
55 | if (!esc) |
56 | return log_oom(); | |
57 | ||
58 | printf("%.*s=%s\n", (int)(sep-s), s, esc); | |
59 | return 0; | |
60 | } | |
61 | ||
32baf64d | 62 | int verb_show_environment(int argc, char *argv[], void *userdata) { |
daf71ef6 LP |
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 | ||
384c2c32 | 73 | pager_open(arg_pager_flags); |
daf71ef6 LP |
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 | ||
5ef599b3 JH |
83 | if (OUTPUT_MODE_IS_JSON(arg_output)) { |
84 | _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; | |
5ef599b3 JH |
85 | |
86 | r = json_transform_message(reply, &v); | |
daf71ef6 LP |
87 | if (r < 0) |
88 | return r; | |
5ef599b3 | 89 | |
92b29166 | 90 | json_variant_dump(v, output_mode_to_json_format_flags(arg_output), stdout, NULL); |
5ef599b3 JH |
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); | |
daf71ef6 | 99 | } |
daf71ef6 LP |
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 | ||
a4ccce22 ZJS |
108 | static void invalid_callback(const char *p, void *userdata) { |
109 | _cleanup_free_ char *t = cescape(p); | |
edfa5517 | 110 | |
a4ccce22 ZJS |
111 | log_debug("Ignoring invalid environment assignment \"%s\".", strnull(t)); |
112 | } | |
113 | ||
32baf64d | 114 | int verb_set_environment(int argc, char *argv[], void *userdata) { |
daf71ef6 LP |
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 | ||
32baf64d | 149 | int verb_import_environment(int argc, char *argv[], void *userdata) { |
daf71ef6 LP |
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 | ||
a4ccce22 | 165 | if (argc < 2) { |
32854f70 | 166 | log_warning("Calling import-environment without a list of variable names is deprecated."); |
edfa5517 | 167 | |
32854f70 | 168 | _cleanup_strv_free_ char **copy = strv_copy(environ); |
a4ccce22 ZJS |
169 | if (!copy) |
170 | return log_oom(); | |
edfa5517 | 171 | |
a4ccce22 | 172 | strv_env_clean_with_callback(copy, invalid_callback, NULL); |
edfa5517 | 173 | |
e9155cd0 ZJS |
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 | ||
a4ccce22 ZJS |
179 | r = sd_bus_message_append_strv(m, copy); |
180 | ||
181 | } else { | |
daf71ef6 LP |
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)) | |
c4899ea4 ZJS |
189 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
190 | "Not a valid environment variable name: %s", *a); | |
daf71ef6 | 191 | |
c4899ea4 | 192 | bool found = false; |
daf71ef6 LP |
193 | STRV_FOREACH(b, environ) { |
194 | const char *eq; | |
195 | ||
196 | eq = startswith(*b, *a); | |
197 | if (eq && *eq == '=') { | |
e9155cd0 ZJS |
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 | ||
daf71ef6 LP |
202 | r = sd_bus_message_append(m, "s", *b); |
203 | if (r < 0) | |
204 | return bus_log_create_error(r); | |
205 | ||
c4899ea4 | 206 | found = true; |
daf71ef6 LP |
207 | break; |
208 | } | |
209 | } | |
c4899ea4 ZJS |
210 | |
211 | if (!found) | |
212 | log_notice("Environment variable $%s not set, ignoring.", *a); | |
daf71ef6 LP |
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 | } |