Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include "alloc-util.h"
4 : : #include "bus-error.h"
5 : : #include "bus-unit-util.h"
6 : : #include "bus-util.h"
7 : : #include "cap-list.h"
8 : : #include "cgroup-util.h"
9 : : #include "condition.h"
10 : : #include "cpu-set-util.h"
11 : : #include "escape.h"
12 : : #include "exec-util.h"
13 : : #include "exit-status.h"
14 : : #include "hexdecoct.h"
15 : : #include "hostname-util.h"
16 : : #include "in-addr-util.h"
17 : : #include "ip-protocol-list.h"
18 : : #include "locale-util.h"
19 : : #include "log.h"
20 : : #include "missing_fs.h"
21 : : #include "mountpoint-util.h"
22 : : #include "nsflags.h"
23 : : #include "parse-util.h"
24 : : #include "process-util.h"
25 : : #include "rlimit-util.h"
26 : : #include "securebits-util.h"
27 : : #include "signal-util.h"
28 : : #include "socket-util.h"
29 : : #include "sort-util.h"
30 : : #include "string-util.h"
31 : : #include "syslog-util.h"
32 : : #include "terminal-util.h"
33 : : #include "unit-def.h"
34 : : #include "user-util.h"
35 : : #include "utf8.h"
36 : :
37 : 0 : int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
38 [ # # ]: 0 : assert(message);
39 [ # # ]: 0 : assert(u);
40 : :
41 : 0 : u->machine = NULL;
42 : :
43 : 0 : return sd_bus_message_read(
44 : : message,
45 : : "(ssssssouso)",
46 : : &u->id,
47 : : &u->description,
48 : : &u->load_state,
49 : : &u->active_state,
50 : : &u->sub_state,
51 : : &u->following,
52 : : &u->unit_path,
53 : : &u->job_id,
54 : : &u->job_type,
55 : : &u->job_path);
56 : : }
57 : :
58 : : #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
59 : : static int bus_append_##parse_func( \
60 : : sd_bus_message *m, \
61 : : const char *field, \
62 : : const char *eq) { \
63 : : type val; \
64 : : int r; \
65 : : \
66 : : r = parse_func(eq, &val); \
67 : : if (r < 0) \
68 : : return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
69 : : \
70 : : r = sd_bus_message_append(m, "(sv)", field, \
71 : : bus_type, (cast_type) val); \
72 : : if (r < 0) \
73 : : return bus_log_create_error(r); \
74 : : \
75 : : return 1; \
76 : : }
77 : :
78 : : #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
79 : : static int bus_append_##parse_func( \
80 : : sd_bus_message *m, \
81 : : const char *field, \
82 : : const char *eq) { \
83 : : int r; \
84 : : \
85 : : r = parse_func(eq); \
86 : : if (r < 0) \
87 : : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
88 : : \
89 : : r = sd_bus_message_append(m, "(sv)", field, \
90 : : bus_type, (int32_t) r); \
91 : : if (r < 0) \
92 : : return bus_log_create_error(r); \
93 : : \
94 : : return 1; \
95 : : }
96 : :
97 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("b", parse_boolean);
# # # # ]
98 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
# # # # ]
99 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
# # # # ]
100 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
# # # # ]
101 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
# # # # ]
102 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", parse_errno);
# # # # ]
103 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
# # # # ]
104 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
# # # # ]
105 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
# # # # ]
106 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
# # # # ]
107 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
# # # # ]
108 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
# # # # ]
109 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
# # # # ]
110 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
# # # # ]
111 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse);
# # # # ]
112 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse);
# # # # ]
113 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
# # # # ]
114 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string);
# # # # ]
115 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
# # # # ]
116 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
# # # # ]
117 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
# # # # ]
118 [ # # # # : 0 : DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
# # # # ]
119 : :
120 : 0 : static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
121 : : int r;
122 : :
123 : 0 : r = sd_bus_message_append(m, "(sv)", field, "s", eq);
124 [ # # ]: 0 : if (r < 0)
125 [ # # ]: 0 : return bus_log_create_error(r);
126 : :
127 : 0 : return 1;
128 : : }
129 : :
130 : 0 : static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
131 : : const char *p;
132 : : int r;
133 : :
134 : 0 : r = sd_bus_message_open_container(m, 'r', "sv");
135 [ # # ]: 0 : if (r < 0)
136 [ # # ]: 0 : return bus_log_create_error(r);
137 : :
138 : 0 : r = sd_bus_message_append_basic(m, 's', field);
139 [ # # ]: 0 : if (r < 0)
140 [ # # ]: 0 : return bus_log_create_error(r);
141 : :
142 : 0 : r = sd_bus_message_open_container(m, 'v', "as");
143 [ # # ]: 0 : if (r < 0)
144 [ # # ]: 0 : return bus_log_create_error(r);
145 : :
146 : 0 : r = sd_bus_message_open_container(m, 'a', "s");
147 [ # # ]: 0 : if (r < 0)
148 [ # # ]: 0 : return bus_log_create_error(r);
149 : :
150 : 0 : for (p = eq;;) {
151 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
152 : :
153 : 0 : r = extract_first_word(&p, &word, NULL, flags);
154 [ # # ]: 0 : if (r == 0)
155 : 0 : break;
156 [ # # ]: 0 : if (r == -ENOMEM)
157 : 0 : return log_oom();
158 [ # # ]: 0 : if (r < 0)
159 [ # # ]: 0 : return log_error_errno(r, "Invalid syntax: %s", eq);
160 : :
161 : 0 : r = sd_bus_message_append_basic(m, 's', word);
162 [ # # ]: 0 : if (r < 0)
163 [ # # ]: 0 : return bus_log_create_error(r);
164 : : }
165 : :
166 : 0 : r = sd_bus_message_close_container(m);
167 [ # # ]: 0 : if (r < 0)
168 [ # # ]: 0 : return bus_log_create_error(r);
169 : :
170 : 0 : r = sd_bus_message_close_container(m);
171 [ # # ]: 0 : if (r < 0)
172 [ # # ]: 0 : return bus_log_create_error(r);
173 : :
174 : 0 : r = sd_bus_message_close_container(m);
175 [ # # ]: 0 : if (r < 0)
176 [ # # ]: 0 : return bus_log_create_error(r);
177 : :
178 : 0 : return 1;
179 : : }
180 : :
181 : 0 : static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
182 : : int r;
183 : :
184 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
185 [ # # ]: 0 : if (r < 0)
186 [ # # ]: 0 : return bus_log_create_error(r);
187 : :
188 : 0 : r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
189 [ # # ]: 0 : if (r < 0)
190 [ # # ]: 0 : return bus_log_create_error(r);
191 : :
192 : 0 : r = sd_bus_message_open_container(m, 'v', "ay");
193 [ # # ]: 0 : if (r < 0)
194 [ # # ]: 0 : return bus_log_create_error(r);
195 : :
196 : 0 : r = sd_bus_message_append_array(m, 'y', buf, n);
197 [ # # ]: 0 : if (r < 0)
198 [ # # ]: 0 : return bus_log_create_error(r);
199 : :
200 : 0 : r = sd_bus_message_close_container(m);
201 [ # # ]: 0 : if (r < 0)
202 [ # # ]: 0 : return bus_log_create_error(r);
203 : :
204 : 0 : r = sd_bus_message_close_container(m);
205 [ # # ]: 0 : if (r < 0)
206 [ # # ]: 0 : return bus_log_create_error(r);
207 : :
208 : 0 : return 1;
209 : : }
210 : :
211 : 0 : static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
212 : : char *n;
213 : : usec_t t;
214 : : size_t l;
215 : : int r;
216 : :
217 : 0 : r = parse_sec(eq, &t);
218 [ # # ]: 0 : if (r < 0)
219 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
220 : :
221 : 0 : l = strlen(field);
222 [ # # # # ]: 0 : n = newa(char, l + 2);
223 : : /* Change suffix Sec → USec */
224 : 0 : strcpy(mempcpy(n, field, l - 3), "USec");
225 : :
226 : 0 : r = sd_bus_message_append(m, "(sv)", n, "t", t);
227 [ # # ]: 0 : if (r < 0)
228 [ # # ]: 0 : return bus_log_create_error(r);
229 : :
230 : 0 : return 1;
231 : : }
232 : :
233 : 0 : static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
234 : : uint64_t v;
235 : : int r;
236 : :
237 : 0 : r = parse_size(eq, base, &v);
238 [ # # ]: 0 : if (r < 0)
239 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
240 : :
241 : 0 : r = sd_bus_message_append(m, "(sv)", field, "t", v);
242 [ # # ]: 0 : if (r < 0)
243 [ # # ]: 0 : return bus_log_create_error(r);
244 : :
245 : 0 : return 1;
246 : : }
247 : :
248 : 0 : static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
249 : 0 : bool explicit_path = false, done = false;
250 : 0 : _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
251 : 0 : _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
252 : 0 : ExecCommandFlags flags = 0;
253 : 0 : bool is_ex_prop = endswith(field, "Ex");
254 : : int r;
255 : :
256 : : do {
257 [ # # # # : 0 : switch (*eq) {
# # ]
258 : :
259 : 0 : case '-':
260 [ # # ]: 0 : if (FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE))
261 : 0 : done = true;
262 : : else {
263 : 0 : flags |= EXEC_COMMAND_IGNORE_FAILURE;
264 : 0 : eq++;
265 : : }
266 : 0 : break;
267 : :
268 : 0 : case '@':
269 [ # # ]: 0 : if (explicit_path)
270 : 0 : done = true;
271 : : else {
272 : 0 : explicit_path = true;
273 : 0 : eq++;
274 : : }
275 : 0 : break;
276 : :
277 : 0 : case ':':
278 [ # # ]: 0 : if (FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND))
279 : 0 : done = true;
280 : : else {
281 : 0 : flags |= EXEC_COMMAND_NO_ENV_EXPAND;
282 : 0 : eq++;
283 : : }
284 : 0 : break;
285 : :
286 : 0 : case '+':
287 [ # # ]: 0 : if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))
288 : 0 : done = true;
289 : : else {
290 : 0 : flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
291 : 0 : eq++;
292 : : }
293 : 0 : break;
294 : :
295 : 0 : case '!':
296 [ # # ]: 0 : if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))
297 : 0 : done = true;
298 [ # # ]: 0 : else if (FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)) {
299 : 0 : flags &= ~EXEC_COMMAND_NO_SETUID;
300 : 0 : flags |= EXEC_COMMAND_AMBIENT_MAGIC;
301 : 0 : eq++;
302 : : } else {
303 : 0 : flags |= EXEC_COMMAND_NO_SETUID;
304 : 0 : eq++;
305 : : }
306 : 0 : break;
307 : :
308 : 0 : default:
309 : 0 : done = true;
310 : 0 : break;
311 : : }
312 [ # # ]: 0 : } while (!done);
313 : :
314 [ # # # # ]: 0 : if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))) {
315 : : /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
316 : 0 : is_ex_prop = true;
317 : 0 : upgraded_name = strjoin(field, "Ex");
318 [ # # ]: 0 : if (!upgraded_name)
319 : 0 : return log_oom();
320 : : }
321 : :
322 [ # # ]: 0 : if (is_ex_prop) {
323 : 0 : r = exec_command_flags_to_strv(flags, &ex_opts);
324 [ # # ]: 0 : if (r < 0)
325 [ # # ]: 0 : return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
326 : : }
327 : :
328 [ # # ]: 0 : if (explicit_path) {
329 : 0 : r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
330 [ # # ]: 0 : if (r < 0)
331 [ # # ]: 0 : return log_error_errno(r, "Failed to parse path: %m");
332 : : }
333 : :
334 : 0 : r = strv_split_extract(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
335 [ # # ]: 0 : if (r < 0)
336 [ # # ]: 0 : return log_error_errno(r, "Failed to parse command line: %m");
337 : :
338 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
339 [ # # ]: 0 : if (r < 0)
340 [ # # ]: 0 : return bus_log_create_error(r);
341 : :
342 [ # # ]: 0 : r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, upgraded_name ?: field);
343 [ # # ]: 0 : if (r < 0)
344 [ # # ]: 0 : return bus_log_create_error(r);
345 : :
346 [ # # ]: 0 : r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
347 [ # # ]: 0 : if (r < 0)
348 [ # # ]: 0 : return bus_log_create_error(r);
349 : :
350 [ # # ]: 0 : r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
351 [ # # ]: 0 : if (r < 0)
352 [ # # ]: 0 : return bus_log_create_error(r);
353 : :
354 [ # # ]: 0 : if (!strv_isempty(l)) {
355 : :
356 [ # # ]: 0 : r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
357 [ # # ]: 0 : if (r < 0)
358 [ # # ]: 0 : return bus_log_create_error(r);
359 : :
360 [ # # ]: 0 : r = sd_bus_message_append(m, "s", path ?: l[0]);
361 [ # # ]: 0 : if (r < 0)
362 [ # # ]: 0 : return bus_log_create_error(r);
363 : :
364 : 0 : r = sd_bus_message_append_strv(m, l);
365 [ # # ]: 0 : if (r < 0)
366 [ # # ]: 0 : return bus_log_create_error(r);
367 : :
368 [ # # ]: 0 : r = is_ex_prop ? sd_bus_message_append_strv(m, ex_opts) : sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
369 [ # # ]: 0 : if (r < 0)
370 [ # # ]: 0 : return bus_log_create_error(r);
371 : :
372 : 0 : r = sd_bus_message_close_container(m);
373 [ # # ]: 0 : if (r < 0)
374 [ # # ]: 0 : return bus_log_create_error(r);
375 : : }
376 : :
377 : 0 : r = sd_bus_message_close_container(m);
378 [ # # ]: 0 : if (r < 0)
379 [ # # ]: 0 : return bus_log_create_error(r);
380 : :
381 : 0 : r = sd_bus_message_close_container(m);
382 [ # # ]: 0 : if (r < 0)
383 [ # # ]: 0 : return bus_log_create_error(r);
384 : :
385 : 0 : r = sd_bus_message_close_container(m);
386 [ # # ]: 0 : if (r < 0)
387 [ # # ]: 0 : return bus_log_create_error(r);
388 : :
389 : 0 : return 1;
390 : : }
391 : :
392 : 0 : static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
393 : : int r;
394 : :
395 [ # # ]: 0 : assert(m);
396 [ # # ]: 0 : assert(prefix);
397 : :
398 : 0 : r = sd_bus_message_open_container(m, 'r', "iayu");
399 [ # # ]: 0 : if (r < 0)
400 : 0 : return r;
401 : :
402 : 0 : r = sd_bus_message_append(m, "i", family);
403 [ # # ]: 0 : if (r < 0)
404 : 0 : return r;
405 : :
406 : 0 : r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
407 [ # # ]: 0 : if (r < 0)
408 : 0 : return r;
409 : :
410 : 0 : r = sd_bus_message_append(m, "u", prefixlen);
411 [ # # ]: 0 : if (r < 0)
412 : 0 : return r;
413 : :
414 : 0 : return sd_bus_message_close_container(m);
415 : : }
416 : :
417 : 0 : static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
418 : : int r;
419 : :
420 [ # # ]: 0 : if (STR_IN_SET(field, "DevicePolicy", "Slice"))
421 : :
422 : 0 : return bus_append_string(m, field, eq);
423 : :
424 [ # # ]: 0 : if (STR_IN_SET(field,
425 : : "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
426 : : "TasksAccounting", "IPAccounting"))
427 : :
428 : 0 : return bus_append_parse_boolean(m, field, eq);
429 : :
430 [ # # ]: 0 : if (STR_IN_SET(field, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
431 : :
432 : 0 : return bus_append_cg_weight_parse(m, field, eq);
433 : :
434 [ # # ]: 0 : if (STR_IN_SET(field, "CPUShares", "StartupCPUShares"))
435 : :
436 : 0 : return bus_append_cg_cpu_shares_parse(m, field, eq);
437 : :
438 [ # # ]: 0 : if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight"))
439 : :
440 : 0 : return bus_append_cg_blkio_weight_parse(m, field, eq);
441 : :
442 [ # # ]: 0 : if (streq(field, "DisableControllers"))
443 : :
444 : 0 : return bus_append_strv(m, "DisableControllers", eq, EXTRACT_UNQUOTE);
445 : :
446 [ # # ]: 0 : if (streq(field, "Delegate")) {
447 : :
448 : 0 : r = parse_boolean(eq);
449 [ # # ]: 0 : if (r < 0)
450 : 0 : return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_UNQUOTE);
451 : :
452 : 0 : r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
453 [ # # ]: 0 : if (r < 0)
454 [ # # ]: 0 : return bus_log_create_error(r);
455 : :
456 : 0 : return 1;
457 : : }
458 : :
459 [ # # ]: 0 : if (STR_IN_SET(field, "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
460 : :
461 [ # # # # ]: 0 : if (isempty(eq) || streq(eq, "infinity")) {
462 : 0 : r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
463 [ # # ]: 0 : if (r < 0)
464 [ # # ]: 0 : return bus_log_create_error(r);
465 : 0 : return 1;
466 : : }
467 : :
468 : 0 : r = parse_permille(eq);
469 [ # # ]: 0 : if (r >= 0) {
470 : : char *n;
471 : :
472 : : /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
473 : : * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
474 : : * size can be determined server-side. */
475 : :
476 [ # # # # : 0 : n = strjoina(field, "Scale");
# # # # #
# # # ]
477 : 0 : r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
478 [ # # ]: 0 : if (r < 0)
479 [ # # ]: 0 : return bus_log_create_error(r);
480 : :
481 : 0 : return 1;
482 : : }
483 : :
484 [ # # ]: 0 : if (streq(field, "TasksMax"))
485 : 0 : return bus_append_safe_atou64(m, field, eq);
486 : :
487 : 0 : return bus_append_parse_size(m, field, eq, 1024);
488 : : }
489 : :
490 [ # # ]: 0 : if (streq(field, "CPUQuota")) {
491 : :
492 [ # # ]: 0 : if (isempty(eq))
493 : 0 : r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
494 : : else {
495 : 0 : r = parse_permille_unbounded(eq);
496 [ # # ]: 0 : if (r == 0)
497 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
498 : : "CPU quota too small.");
499 [ # # ]: 0 : if (r < 0)
500 [ # # ]: 0 : return log_error_errno(r, "CPU quota '%s' invalid.", eq);
501 : :
502 : 0 : r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U));
503 : : }
504 : :
505 [ # # ]: 0 : if (r < 0)
506 [ # # ]: 0 : return bus_log_create_error(r);
507 : :
508 : 0 : return 1;
509 : : }
510 : :
511 [ # # ]: 0 : if (streq(field, "CPUQuotaPeriodSec")) {
512 : 0 : usec_t u = USEC_INFINITY;
513 : :
514 : 0 : r = parse_sec_def_infinity(eq, &u);
515 [ # # ]: 0 : if (r < 0)
516 [ # # ]: 0 : return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
517 : :
518 : 0 : r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
519 [ # # ]: 0 : if (r < 0)
520 [ # # ]: 0 : return bus_log_create_error(r);
521 : :
522 : 0 : return 1;
523 : : }
524 : :
525 [ # # ]: 0 : if (streq(field, "DeviceAllow")) {
526 : :
527 [ # # ]: 0 : if (isempty(eq))
528 : 0 : r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
529 : : else {
530 : 0 : const char *path = eq, *rwm = NULL, *e;
531 : :
532 : 0 : e = strchr(eq, ' ');
533 [ # # ]: 0 : if (e) {
534 : 0 : path = strndupa(eq, e - eq);
535 : 0 : rwm = e+1;
536 : : }
537 : :
538 : 0 : r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
539 : : }
540 : :
541 [ # # ]: 0 : if (r < 0)
542 [ # # ]: 0 : return bus_log_create_error(r);
543 : :
544 : 0 : return 1;
545 : : }
546 : :
547 [ # # # # ]: 0 : if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
548 : :
549 [ # # ]: 0 : if (isempty(eq))
550 : 0 : r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
551 : : else {
552 : : const char *path, *bandwidth, *e;
553 : : uint64_t bytes;
554 : :
555 : 0 : e = strchr(eq, ' ');
556 [ # # ]: 0 : if (!e)
557 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
558 : : "Failed to parse %s value %s.",
559 : : field, eq);
560 : :
561 : 0 : path = strndupa(eq, e - eq);
562 : 0 : bandwidth = e+1;
563 : :
564 [ # # ]: 0 : if (streq(bandwidth, "infinity"))
565 : 0 : bytes = CGROUP_LIMIT_MAX;
566 : : else {
567 : 0 : r = parse_size(bandwidth, 1000, &bytes);
568 [ # # ]: 0 : if (r < 0)
569 [ # # ]: 0 : return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
570 : : }
571 : :
572 : 0 : r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
573 : : }
574 : :
575 [ # # ]: 0 : if (r < 0)
576 [ # # ]: 0 : return bus_log_create_error(r);
577 : :
578 : 0 : return 1;
579 : : }
580 : :
581 [ # # ]: 0 : if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) {
582 : :
583 [ # # ]: 0 : if (isempty(eq))
584 : 0 : r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
585 : : else {
586 : : const char *path, *weight, *e;
587 : : uint64_t u;
588 : :
589 : 0 : e = strchr(eq, ' ');
590 [ # # ]: 0 : if (!e)
591 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
592 : : "Failed to parse %s value %s.",
593 : : field, eq);
594 : :
595 : 0 : path = strndupa(eq, e - eq);
596 : 0 : weight = e+1;
597 : :
598 : 0 : r = safe_atou64(weight, &u);
599 [ # # ]: 0 : if (r < 0)
600 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
601 : :
602 : 0 : r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
603 : : }
604 : :
605 [ # # ]: 0 : if (r < 0)
606 [ # # ]: 0 : return bus_log_create_error(r);
607 : :
608 : 0 : return 1;
609 : : }
610 : :
611 [ # # ]: 0 : if (streq(field, "IODeviceLatencyTargetSec")) {
612 : 0 : const char *field_usec = "IODeviceLatencyTargetUSec";
613 : :
614 [ # # ]: 0 : if (isempty(eq))
615 : 0 : r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
616 : : else {
617 : : const char *path, *target, *e;
618 : : usec_t usec;
619 : :
620 : 0 : e = strchr(eq, ' ');
621 [ # # ]: 0 : if (!e)
622 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
623 : : "Failed to parse %s value %s.",
624 : : field, eq);
625 : :
626 : 0 : path = strndupa(eq, e - eq);
627 : 0 : target = e+1;
628 : :
629 : 0 : r = parse_sec(target, &usec);
630 [ # # ]: 0 : if (r < 0)
631 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
632 : :
633 : 0 : r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
634 : : }
635 : :
636 [ # # ]: 0 : if (r < 0)
637 [ # # ]: 0 : return bus_log_create_error(r);
638 : :
639 : 0 : return 1;
640 : : }
641 : :
642 [ # # ]: 0 : if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) {
643 : : unsigned char prefixlen;
644 : 0 : union in_addr_union prefix = {};
645 : : int family;
646 : :
647 [ # # ]: 0 : if (isempty(eq)) {
648 : 0 : r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
649 [ # # ]: 0 : if (r < 0)
650 [ # # ]: 0 : return bus_log_create_error(r);
651 : :
652 : 0 : return 1;
653 : : }
654 : :
655 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
656 [ # # ]: 0 : if (r < 0)
657 [ # # ]: 0 : return bus_log_create_error(r);
658 : :
659 : 0 : r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
660 [ # # ]: 0 : if (r < 0)
661 [ # # ]: 0 : return bus_log_create_error(r);
662 : :
663 : 0 : r = sd_bus_message_open_container(m, 'v', "a(iayu)");
664 [ # # ]: 0 : if (r < 0)
665 [ # # ]: 0 : return bus_log_create_error(r);
666 : :
667 : 0 : r = sd_bus_message_open_container(m, 'a', "(iayu)");
668 [ # # ]: 0 : if (r < 0)
669 [ # # ]: 0 : return bus_log_create_error(r);
670 : :
671 [ # # ]: 0 : if (streq(eq, "any")) {
672 : : /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
673 : :
674 : 0 : r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
675 [ # # ]: 0 : if (r < 0)
676 [ # # ]: 0 : return bus_log_create_error(r);
677 : :
678 : 0 : r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
679 [ # # ]: 0 : if (r < 0)
680 [ # # ]: 0 : return bus_log_create_error(r);
681 : :
682 [ # # ]: 0 : } else if (is_localhost(eq)) {
683 : : /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
684 : :
685 : 0 : prefix.in.s_addr = htobe32(0x7f000000);
686 : 0 : r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
687 [ # # ]: 0 : if (r < 0)
688 [ # # ]: 0 : return bus_log_create_error(r);
689 : :
690 : 0 : prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
691 : 0 : r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
692 [ # # ]: 0 : if (r < 0)
693 : 0 : return r;
694 : :
695 [ # # ]: 0 : } else if (streq(eq, "link-local")) {
696 : : /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
697 : :
698 : 0 : prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
699 : 0 : r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
700 [ # # ]: 0 : if (r < 0)
701 [ # # ]: 0 : return bus_log_create_error(r);
702 : :
703 : 0 : prefix.in6 = (struct in6_addr) {
704 : 0 : .s6_addr32[0] = htobe32(0xfe800000)
705 : : };
706 : 0 : r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
707 [ # # ]: 0 : if (r < 0)
708 [ # # ]: 0 : return bus_log_create_error(r);
709 : :
710 [ # # ]: 0 : } else if (streq(eq, "multicast")) {
711 : : /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
712 : :
713 : 0 : prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
714 : 0 : r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
715 [ # # ]: 0 : if (r < 0)
716 [ # # ]: 0 : return bus_log_create_error(r);
717 : :
718 : 0 : prefix.in6 = (struct in6_addr) {
719 : 0 : .s6_addr32[0] = htobe32(0xff000000)
720 : : };
721 : 0 : r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
722 [ # # ]: 0 : if (r < 0)
723 [ # # ]: 0 : return bus_log_create_error(r);
724 : :
725 : : } else {
726 : 0 : for (;;) {
727 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
728 : :
729 : 0 : r = extract_first_word(&eq, &word, NULL, 0);
730 [ # # ]: 0 : if (r == 0)
731 : 0 : break;
732 [ # # ]: 0 : if (r == -ENOMEM)
733 : 0 : return log_oom();
734 [ # # ]: 0 : if (r < 0)
735 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s: %s", field, eq);
736 : :
737 : 0 : r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
738 [ # # ]: 0 : if (r < 0)
739 [ # # ]: 0 : return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
740 : :
741 : 0 : r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
742 [ # # ]: 0 : if (r < 0)
743 [ # # ]: 0 : return bus_log_create_error(r);
744 : : }
745 : : }
746 : :
747 : 0 : r = sd_bus_message_close_container(m);
748 [ # # ]: 0 : if (r < 0)
749 [ # # ]: 0 : return bus_log_create_error(r);
750 : :
751 : 0 : r = sd_bus_message_close_container(m);
752 [ # # ]: 0 : if (r < 0)
753 [ # # ]: 0 : return bus_log_create_error(r);
754 : :
755 : 0 : r = sd_bus_message_close_container(m);
756 [ # # ]: 0 : if (r < 0)
757 [ # # ]: 0 : return bus_log_create_error(r);
758 : :
759 : 0 : return 1;
760 : : }
761 : :
762 [ # # ]: 0 : if (STR_IN_SET(field, "IPIngressFilterPath", "IPEgressFilterPath")) {
763 [ # # ]: 0 : if (isempty(eq))
764 : 0 : r = sd_bus_message_append(m, "(sv)", field, "as", 0);
765 : : else
766 : 0 : r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
767 : :
768 [ # # ]: 0 : if (r < 0)
769 [ # # ]: 0 : return bus_log_create_error(r);
770 : :
771 : 0 : return 1;
772 : : }
773 : :
774 : 0 : return 0;
775 : : }
776 : :
777 : 0 : static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
778 : :
779 [ # # ]: 0 : if (streq(field, "Where"))
780 : :
781 : 0 : return bus_append_string(m, field, eq);
782 : :
783 [ # # ]: 0 : if (streq(field, "DirectoryMode"))
784 : :
785 : 0 : return bus_append_parse_mode(m, field, eq);
786 : :
787 [ # # ]: 0 : if (streq(field, "TimeoutIdleSec"))
788 : :
789 : 0 : return bus_append_parse_sec_rename(m, field, eq);
790 : :
791 : 0 : return 0;
792 : : }
793 : :
794 : 0 : static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
795 : : const char *suffix;
796 : : int r;
797 : :
798 [ # # ]: 0 : if (STR_IN_SET(field,
799 : : "User", "Group",
800 : : "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
801 : : "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
802 : : "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
803 : : "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
804 : :
805 : 0 : return bus_append_string(m, field, eq);
806 : :
807 [ # # ]: 0 : if (STR_IN_SET(field,
808 : : "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
809 : : "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
810 : : "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
811 : : "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
812 : : "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
813 : : "ProtectHostname", "RestrictSUIDSGID"))
814 : :
815 : 0 : return bus_append_parse_boolean(m, field, eq);
816 : :
817 [ # # ]: 0 : if (STR_IN_SET(field,
818 : : "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
819 : : "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
820 : : "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
821 : : "SupplementaryGroups", "SystemCallArchitectures"))
822 : :
823 : 0 : return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
824 : :
825 [ # # ]: 0 : if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax"))
826 : :
827 : 0 : return bus_append_log_level_from_string(m, field, eq);
828 : :
829 [ # # ]: 0 : if (streq(field, "SyslogFacility"))
830 : :
831 : 0 : return bus_append_log_facility_unshifted_from_string(m, field, eq);
832 : :
833 [ # # ]: 0 : if (streq(field, "SecureBits"))
834 : :
835 : 0 : return bus_append_secure_bits_from_string(m, field, eq);
836 : :
837 [ # # ]: 0 : if (streq(field, "CPUSchedulingPolicy"))
838 : :
839 : 0 : return bus_append_sched_policy_from_string(m, field, eq);
840 : :
841 [ # # ]: 0 : if (STR_IN_SET(field, "CPUSchedulingPriority", "OOMScoreAdjust"))
842 : :
843 : 0 : return bus_append_safe_atoi(m, field, eq);
844 : :
845 [ # # ]: 0 : if (streq(field, "Nice"))
846 : :
847 : 0 : return bus_append_parse_nice(m, field, eq);
848 : :
849 [ # # ]: 0 : if (streq(field, "SystemCallErrorNumber"))
850 : :
851 : 0 : return bus_append_parse_errno(m, field, eq);
852 : :
853 [ # # ]: 0 : if (streq(field, "IOSchedulingClass"))
854 : :
855 : 0 : return bus_append_ioprio_class_from_string(m, field, eq);
856 : :
857 [ # # ]: 0 : if (streq(field, "IOSchedulingPriority"))
858 : :
859 : 0 : return bus_append_ioprio_parse_priority(m, field, eq);
860 : :
861 [ # # ]: 0 : if (STR_IN_SET(field,
862 : : "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
863 : : "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
864 : :
865 : 0 : return bus_append_parse_mode(m, field, eq);
866 : :
867 [ # # ]: 0 : if (streq(field, "TimerSlackNSec"))
868 : :
869 : 0 : return bus_append_parse_nsec(m, field, eq);
870 : :
871 [ # # ]: 0 : if (streq(field, "LogRateLimitIntervalSec"))
872 : :
873 : 0 : return bus_append_parse_sec_rename(m, field, eq);
874 : :
875 [ # # ]: 0 : if (streq(field, "LogRateLimitBurst"))
876 : :
877 : 0 : return bus_append_safe_atou(m, field, eq);
878 : :
879 [ # # ]: 0 : if (streq(field, "MountFlags"))
880 : :
881 : 0 : return bus_append_mount_propagation_flags_from_string(m, field, eq);
882 : :
883 [ # # ]: 0 : if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment"))
884 : :
885 : 0 : return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
886 : :
887 [ # # ]: 0 : if (streq(field, "EnvironmentFile")) {
888 : :
889 [ # # ]: 0 : if (isempty(eq))
890 : 0 : r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
891 : : else
892 : 0 : r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
893 : 0 : eq[0] == '-' ? eq + 1 : eq,
894 [ # # ]: 0 : eq[0] == '-');
895 [ # # ]: 0 : if (r < 0)
896 [ # # ]: 0 : return bus_log_create_error(r);
897 : :
898 : 0 : return 1;
899 : : }
900 : :
901 [ # # ]: 0 : if (streq(field, "LogExtraFields")) {
902 : :
903 : 0 : r = sd_bus_message_open_container(m, 'r', "sv");
904 [ # # ]: 0 : if (r < 0)
905 [ # # ]: 0 : return bus_log_create_error(r);
906 : :
907 : 0 : r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
908 [ # # ]: 0 : if (r < 0)
909 [ # # ]: 0 : return bus_log_create_error(r);
910 : :
911 : 0 : r = sd_bus_message_open_container(m, 'v', "aay");
912 [ # # ]: 0 : if (r < 0)
913 [ # # ]: 0 : return bus_log_create_error(r);
914 : :
915 : 0 : r = sd_bus_message_open_container(m, 'a', "ay");
916 [ # # ]: 0 : if (r < 0)
917 [ # # ]: 0 : return bus_log_create_error(r);
918 : :
919 : 0 : r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
920 [ # # ]: 0 : if (r < 0)
921 [ # # ]: 0 : return bus_log_create_error(r);
922 : :
923 : 0 : r = sd_bus_message_close_container(m);
924 [ # # ]: 0 : if (r < 0)
925 [ # # ]: 0 : return bus_log_create_error(r);
926 : :
927 : 0 : r = sd_bus_message_close_container(m);
928 [ # # ]: 0 : if (r < 0)
929 [ # # ]: 0 : return bus_log_create_error(r);
930 : :
931 : 0 : r = sd_bus_message_close_container(m);
932 [ # # ]: 0 : if (r < 0)
933 [ # # ]: 0 : return bus_log_create_error(r);
934 : :
935 : 0 : return 1;
936 : : }
937 : :
938 [ # # ]: 0 : if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) {
939 : : const char *n, *appended;
940 : :
941 [ # # ]: 0 : if ((n = startswith(eq, "fd:"))) {
942 [ # # # # : 0 : appended = strjoina(field, "FileDescriptorName");
# # # # #
# # # ]
943 : 0 : r = sd_bus_message_append(m, "(sv)", appended, "s", n);
944 [ # # ]: 0 : } else if ((n = startswith(eq, "file:"))) {
945 [ # # # # : 0 : appended = strjoina(field, "File");
# # # # #
# # # ]
946 : 0 : r = sd_bus_message_append(m, "(sv)", appended, "s", n);
947 [ # # ]: 0 : } else if ((n = startswith(eq, "append:"))) {
948 [ # # # # : 0 : appended = strjoina(field, "FileToAppend");
# # # # #
# # # ]
949 : 0 : r = sd_bus_message_append(m, "(sv)", appended, "s", n);
950 : : } else
951 : 0 : r = sd_bus_message_append(m, "(sv)", field, "s", eq);
952 [ # # ]: 0 : if (r < 0)
953 [ # # ]: 0 : return bus_log_create_error(r);
954 : :
955 : 0 : return 1;
956 : : }
957 : :
958 [ # # ]: 0 : if (streq(field, "StandardInputText")) {
959 : 0 : _cleanup_free_ char *unescaped = NULL;
960 : :
961 : 0 : r = cunescape(eq, 0, &unescaped);
962 [ # # ]: 0 : if (r < 0)
963 [ # # ]: 0 : return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
964 : :
965 [ # # ]: 0 : if (!strextend(&unescaped, "\n", NULL))
966 : 0 : return log_oom();
967 : :
968 : : /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
969 : : * interface anyway */
970 : :
971 : 0 : return bus_append_byte_array(m, field, unescaped, strlen(unescaped));
972 : : }
973 : :
974 [ # # ]: 0 : if (streq(field, "StandardInputData")) {
975 : 0 : _cleanup_free_ void *decoded = NULL;
976 : : size_t sz;
977 : :
978 : 0 : r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
979 [ # # ]: 0 : if (r < 0)
980 [ # # ]: 0 : return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
981 : :
982 : 0 : return bus_append_byte_array(m, field, decoded, sz);
983 : : }
984 : :
985 [ # # ]: 0 : if ((suffix = startswith(field, "Limit"))) {
986 : : int rl;
987 : :
988 : 0 : rl = rlimit_from_string(suffix);
989 [ # # ]: 0 : if (rl >= 0) {
990 : : const char *sn;
991 : : struct rlimit l;
992 : :
993 : 0 : r = rlimit_parse(rl, eq, &l);
994 [ # # ]: 0 : if (r < 0)
995 [ # # ]: 0 : return log_error_errno(r, "Failed to parse resource limit: %s", eq);
996 : :
997 : 0 : r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
998 [ # # ]: 0 : if (r < 0)
999 [ # # ]: 0 : return bus_log_create_error(r);
1000 : :
1001 [ # # # # : 0 : sn = strjoina(field, "Soft");
# # # # #
# # # ]
1002 : 0 : r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
1003 [ # # ]: 0 : if (r < 0)
1004 [ # # ]: 0 : return bus_log_create_error(r);
1005 : :
1006 : 0 : return 1;
1007 : : }
1008 : : }
1009 : :
1010 [ # # ]: 0 : if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
1011 : 0 : int ignore = 0;
1012 : 0 : const char *s = eq;
1013 : :
1014 [ # # ]: 0 : if (eq[0] == '-') {
1015 : 0 : ignore = 1;
1016 : 0 : s = eq + 1;
1017 : : }
1018 : :
1019 : 0 : r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
1020 [ # # ]: 0 : if (r < 0)
1021 [ # # ]: 0 : return bus_log_create_error(r);
1022 : :
1023 : 0 : return 1;
1024 : : }
1025 : :
1026 [ # # ]: 0 : if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) {
1027 : 0 : uint64_t sum = 0;
1028 : 0 : bool invert = false;
1029 : 0 : const char *p = eq;
1030 : :
1031 [ # # ]: 0 : if (*p == '~') {
1032 : 0 : invert = true;
1033 : 0 : p++;
1034 : : }
1035 : :
1036 : 0 : r = capability_set_from_string(p, &sum);
1037 [ # # ]: 0 : if (r < 0)
1038 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
1039 : :
1040 [ # # ]: 0 : sum = invert ? ~sum : sum;
1041 : :
1042 : 0 : r = sd_bus_message_append(m, "(sv)", field, "t", sum);
1043 [ # # ]: 0 : if (r < 0)
1044 [ # # ]: 0 : return bus_log_create_error(r);
1045 : :
1046 : 0 : return 1;
1047 : : }
1048 : :
1049 [ # # ]: 0 : if (streq(field, "CPUAffinity")) {
1050 : 0 : _cleanup_(cpu_set_reset) CPUSet cpuset = {};
1051 : 0 : _cleanup_free_ uint8_t *array = NULL;
1052 : : size_t allocated;
1053 : :
1054 : 0 : r = parse_cpu_set(eq, &cpuset);
1055 [ # # ]: 0 : if (r < 0)
1056 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1057 : :
1058 : 0 : r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1059 [ # # ]: 0 : if (r < 0)
1060 [ # # ]: 0 : return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1061 : :
1062 : 0 : return bus_append_byte_array(m, field, array, allocated);
1063 : : }
1064 : :
1065 [ # # ]: 0 : if (streq(field, "NUMAPolicy")) {
1066 : 0 : r = mpol_from_string(eq);
1067 [ # # ]: 0 : if (r < 0)
1068 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1069 : :
1070 : 0 : r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1071 [ # # ]: 0 : if (r < 0)
1072 [ # # ]: 0 : return bus_log_create_error(r);
1073 : :
1074 : 0 : return 1;
1075 : : }
1076 : :
1077 [ # # ]: 0 : if (streq(field, "NUMAMask")) {
1078 : 0 : _cleanup_(cpu_set_reset) CPUSet nodes = {};
1079 : 0 : _cleanup_free_ uint8_t *array = NULL;
1080 : : size_t allocated;
1081 : :
1082 : 0 : r = parse_cpu_set(eq, &nodes);
1083 [ # # ]: 0 : if (r < 0)
1084 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1085 : :
1086 : 0 : r = cpu_set_to_dbus(&nodes, &array, &allocated);
1087 [ # # ]: 0 : if (r < 0)
1088 [ # # ]: 0 : return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1089 : :
1090 : 0 : return bus_append_byte_array(m, field, array, allocated);
1091 : : }
1092 : :
1093 [ # # ]: 0 : if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
1094 : 0 : int whitelist = 1;
1095 : 0 : const char *p = eq;
1096 : :
1097 [ # # ]: 0 : if (*p == '~') {
1098 : 0 : whitelist = 0;
1099 : 0 : p++;
1100 : : }
1101 : :
1102 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1103 [ # # ]: 0 : if (r < 0)
1104 [ # # ]: 0 : return bus_log_create_error(r);
1105 : :
1106 : 0 : r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1107 [ # # ]: 0 : if (r < 0)
1108 [ # # ]: 0 : return bus_log_create_error(r);
1109 : :
1110 : 0 : r = sd_bus_message_open_container(m, 'v', "(bas)");
1111 [ # # ]: 0 : if (r < 0)
1112 [ # # ]: 0 : return bus_log_create_error(r);
1113 : :
1114 : 0 : r = sd_bus_message_open_container(m, 'r', "bas");
1115 [ # # ]: 0 : if (r < 0)
1116 [ # # ]: 0 : return bus_log_create_error(r);
1117 : :
1118 : 0 : r = sd_bus_message_append_basic(m, 'b', &whitelist);
1119 [ # # ]: 0 : if (r < 0)
1120 [ # # ]: 0 : return bus_log_create_error(r);
1121 : :
1122 : 0 : r = sd_bus_message_open_container(m, 'a', "s");
1123 [ # # ]: 0 : if (r < 0)
1124 [ # # ]: 0 : return bus_log_create_error(r);
1125 : :
1126 : 0 : for (;;) {
1127 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
1128 : :
1129 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1130 [ # # ]: 0 : if (r == 0)
1131 : 0 : break;
1132 [ # # ]: 0 : if (r == -ENOMEM)
1133 : 0 : return log_oom();
1134 [ # # ]: 0 : if (r < 0)
1135 [ # # ]: 0 : return log_error_errno(r, "Invalid syntax: %s", eq);
1136 : :
1137 : 0 : r = sd_bus_message_append_basic(m, 's', word);
1138 [ # # ]: 0 : if (r < 0)
1139 [ # # ]: 0 : return bus_log_create_error(r);
1140 : : }
1141 : :
1142 : 0 : r = sd_bus_message_close_container(m);
1143 [ # # ]: 0 : if (r < 0)
1144 [ # # ]: 0 : return bus_log_create_error(r);
1145 : :
1146 : 0 : r = sd_bus_message_close_container(m);
1147 [ # # ]: 0 : if (r < 0)
1148 [ # # ]: 0 : return bus_log_create_error(r);
1149 : :
1150 : 0 : r = sd_bus_message_close_container(m);
1151 [ # # ]: 0 : if (r < 0)
1152 [ # # ]: 0 : return bus_log_create_error(r);
1153 : :
1154 : 0 : r = sd_bus_message_close_container(m);
1155 [ # # ]: 0 : if (r < 0)
1156 [ # # ]: 0 : return bus_log_create_error(r);
1157 : :
1158 : 0 : return 1;
1159 : : }
1160 : :
1161 [ # # ]: 0 : if (streq(field, "RestrictNamespaces")) {
1162 : 0 : bool invert = false;
1163 : : unsigned long flags;
1164 : :
1165 : 0 : r = parse_boolean(eq);
1166 [ # # ]: 0 : if (r > 0)
1167 : 0 : flags = 0;
1168 [ # # ]: 0 : else if (r == 0)
1169 : 0 : flags = NAMESPACE_FLAGS_ALL;
1170 : : else {
1171 [ # # ]: 0 : if (eq[0] == '~') {
1172 : 0 : invert = true;
1173 : 0 : eq++;
1174 : : }
1175 : :
1176 : 0 : r = namespace_flags_from_string(eq, &flags);
1177 [ # # ]: 0 : if (r < 0)
1178 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1179 : : }
1180 : :
1181 [ # # ]: 0 : if (invert)
1182 : 0 : flags = (~flags) & NAMESPACE_FLAGS_ALL;
1183 : :
1184 : 0 : r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1185 [ # # ]: 0 : if (r < 0)
1186 [ # # ]: 0 : return bus_log_create_error(r);
1187 : :
1188 : 0 : return 1;
1189 : : }
1190 : :
1191 [ # # ]: 0 : if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) {
1192 : 0 : const char *p = eq;
1193 : :
1194 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1195 [ # # ]: 0 : if (r < 0)
1196 [ # # ]: 0 : return bus_log_create_error(r);
1197 : :
1198 : 0 : r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1199 [ # # ]: 0 : if (r < 0)
1200 [ # # ]: 0 : return bus_log_create_error(r);
1201 : :
1202 : 0 : r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1203 [ # # ]: 0 : if (r < 0)
1204 [ # # ]: 0 : return bus_log_create_error(r);
1205 : :
1206 : 0 : r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1207 [ # # ]: 0 : if (r < 0)
1208 [ # # ]: 0 : return bus_log_create_error(r);
1209 : :
1210 : 0 : for (;;) {
1211 [ # # # # : 0 : _cleanup_free_ char *source = NULL, *destination = NULL;
# # ]
1212 : 0 : char *s = NULL, *d = NULL;
1213 : 0 : bool ignore_enoent = false;
1214 : 0 : uint64_t flags = MS_REC;
1215 : :
1216 : 0 : r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1217 [ # # ]: 0 : if (r < 0)
1218 [ # # ]: 0 : return log_error_errno(r, "Failed to parse argument: %m");
1219 [ # # ]: 0 : if (r == 0)
1220 : 0 : break;
1221 : :
1222 : 0 : s = source;
1223 [ # # ]: 0 : if (s[0] == '-') {
1224 : 0 : ignore_enoent = true;
1225 : 0 : s++;
1226 : : }
1227 : :
1228 [ # # # # ]: 0 : if (p && p[-1] == ':') {
1229 : 0 : r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1230 [ # # ]: 0 : if (r < 0)
1231 [ # # ]: 0 : return log_error_errno(r, "Failed to parse argument: %m");
1232 [ # # ]: 0 : if (r == 0)
1233 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1234 : : "Missing argument after ':': %s",
1235 : : eq);
1236 : :
1237 : 0 : d = destination;
1238 : :
1239 [ # # # # ]: 0 : if (p && p[-1] == ':') {
1240 [ # # ]: 0 : _cleanup_free_ char *options = NULL;
1241 : :
1242 : 0 : r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
1243 [ # # ]: 0 : if (r < 0)
1244 [ # # ]: 0 : return log_error_errno(r, "Failed to parse argument: %m");
1245 : :
1246 [ # # # # ]: 0 : if (isempty(options) || streq(options, "rbind"))
1247 : 0 : flags = MS_REC;
1248 [ # # ]: 0 : else if (streq(options, "norbind"))
1249 : 0 : flags = 0;
1250 : : else
1251 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1252 : : "Unknown options: %s",
1253 : : eq);
1254 : : }
1255 : : } else
1256 : 0 : d = s;
1257 : :
1258 : 0 : r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1259 [ # # ]: 0 : if (r < 0)
1260 [ # # ]: 0 : return bus_log_create_error(r);
1261 : : }
1262 : :
1263 : 0 : r = sd_bus_message_close_container(m);
1264 [ # # ]: 0 : if (r < 0)
1265 [ # # ]: 0 : return bus_log_create_error(r);
1266 : :
1267 : 0 : r = sd_bus_message_close_container(m);
1268 [ # # ]: 0 : if (r < 0)
1269 [ # # ]: 0 : return bus_log_create_error(r);
1270 : :
1271 : 0 : r = sd_bus_message_close_container(m);
1272 [ # # ]: 0 : if (r < 0)
1273 [ # # ]: 0 : return bus_log_create_error(r);
1274 : :
1275 : 0 : return 1;
1276 : : }
1277 : :
1278 [ # # ]: 0 : if (streq(field, "TemporaryFileSystem")) {
1279 : 0 : const char *p = eq;
1280 : :
1281 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1282 [ # # ]: 0 : if (r < 0)
1283 [ # # ]: 0 : return bus_log_create_error(r);
1284 : :
1285 : 0 : r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1286 [ # # ]: 0 : if (r < 0)
1287 [ # # ]: 0 : return bus_log_create_error(r);
1288 : :
1289 : 0 : r = sd_bus_message_open_container(m, 'v', "a(ss)");
1290 [ # # ]: 0 : if (r < 0)
1291 [ # # ]: 0 : return bus_log_create_error(r);
1292 : :
1293 : 0 : r = sd_bus_message_open_container(m, 'a', "(ss)");
1294 [ # # ]: 0 : if (r < 0)
1295 [ # # ]: 0 : return bus_log_create_error(r);
1296 : :
1297 : 0 : for (;;) {
1298 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *path = NULL;
# # ]
1299 : : const char *w;
1300 : :
1301 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1302 [ # # ]: 0 : if (r < 0)
1303 [ # # ]: 0 : return log_error_errno(r, "Failed to parse argument: %m");
1304 [ # # ]: 0 : if (r == 0)
1305 : 0 : break;
1306 : :
1307 : 0 : w = word;
1308 : 0 : r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1309 [ # # ]: 0 : if (r < 0)
1310 [ # # ]: 0 : return log_error_errno(r, "Failed to parse argument: %m");
1311 [ # # ]: 0 : if (r == 0)
1312 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1313 : : "Failed to parse argument: %s",
1314 : : p);
1315 : :
1316 : 0 : r = sd_bus_message_append(m, "(ss)", path, w);
1317 [ # # ]: 0 : if (r < 0)
1318 [ # # ]: 0 : return bus_log_create_error(r);
1319 : : }
1320 : :
1321 : 0 : r = sd_bus_message_close_container(m);
1322 [ # # ]: 0 : if (r < 0)
1323 [ # # ]: 0 : return bus_log_create_error(r);
1324 : :
1325 : 0 : r = sd_bus_message_close_container(m);
1326 [ # # ]: 0 : if (r < 0)
1327 [ # # ]: 0 : return bus_log_create_error(r);
1328 : :
1329 : 0 : r = sd_bus_message_close_container(m);
1330 [ # # ]: 0 : if (r < 0)
1331 [ # # ]: 0 : return bus_log_create_error(r);
1332 : :
1333 : 0 : return 1;
1334 : : }
1335 : :
1336 : 0 : return 0;
1337 : : }
1338 : :
1339 : 0 : static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
1340 : :
1341 [ # # ]: 0 : if (streq(field, "KillMode"))
1342 : :
1343 : 0 : return bus_append_string(m, field, eq);
1344 : :
1345 [ # # ]: 0 : if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
1346 : :
1347 : 0 : return bus_append_parse_boolean(m, field, eq);
1348 : :
1349 [ # # ]: 0 : if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1350 : :
1351 : 0 : return bus_append_signal_from_string(m, field, eq);
1352 : :
1353 : 0 : return 0;
1354 : : }
1355 : :
1356 : 0 : static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
1357 : :
1358 [ # # ]: 0 : if (STR_IN_SET(field, "What", "Where", "Options", "Type"))
1359 : :
1360 : 0 : return bus_append_string(m, field, eq);
1361 : :
1362 [ # # ]: 0 : if (streq(field, "TimeoutSec"))
1363 : :
1364 : 0 : return bus_append_parse_sec_rename(m, field, eq);
1365 : :
1366 [ # # ]: 0 : if (streq(field, "DirectoryMode"))
1367 : :
1368 : 0 : return bus_append_parse_mode(m, field, eq);
1369 : :
1370 [ # # ]: 0 : if (STR_IN_SET(field, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1371 : :
1372 : 0 : return bus_append_parse_boolean(m, field, eq);
1373 : :
1374 : 0 : return 0;
1375 : : }
1376 : :
1377 : 0 : static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1378 : : int r;
1379 : :
1380 [ # # ]: 0 : if (streq(field, "MakeDirectory"))
1381 : :
1382 : 0 : return bus_append_parse_boolean(m, field, eq);
1383 : :
1384 [ # # ]: 0 : if (streq(field, "DirectoryMode"))
1385 : :
1386 : 0 : return bus_append_parse_mode(m, field, eq);
1387 : :
1388 [ # # ]: 0 : if (STR_IN_SET(field,
1389 : : "PathExists", "PathExistsGlob", "PathChanged",
1390 : : "PathModified", "DirectoryNotEmpty")) {
1391 : :
1392 [ # # ]: 0 : if (isempty(eq))
1393 : 0 : r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1394 : : else
1395 : 0 : r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1396 [ # # ]: 0 : if (r < 0)
1397 [ # # ]: 0 : return bus_log_create_error(r);
1398 : :
1399 : 0 : return 1;
1400 : : }
1401 : :
1402 : 0 : return 0;
1403 : : }
1404 : :
1405 : 0 : static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
1406 : : int r;
1407 : :
1408 [ # # ]: 0 : if (STR_IN_SET(field,
1409 : : "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1410 : : "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1411 : :
1412 : 0 : return bus_append_string(m, field, eq);
1413 : :
1414 [ # # ]: 0 : if (STR_IN_SET(field, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1415 : :
1416 : 0 : return bus_append_parse_boolean(m, field, eq);
1417 : :
1418 [ # # ]: 0 : if (STR_IN_SET(field, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1419 : :
1420 : 0 : return bus_append_parse_sec_rename(m, field, eq);
1421 : :
1422 [ # # ]: 0 : if (streq(field, "TimeoutSec")) {
1423 : :
1424 : 0 : r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1425 [ # # ]: 0 : if (r < 0)
1426 : 0 : return r;
1427 : :
1428 : 0 : return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1429 : : }
1430 : :
1431 [ # # ]: 0 : if (streq(field, "FileDescriptorStoreMax"))
1432 : :
1433 : 0 : return bus_append_safe_atou(m, field, eq);
1434 : :
1435 [ # # ]: 0 : if (STR_IN_SET(field,
1436 : : "ExecCondition", "ExecStartPre", "ExecStart", "ExecStartPost",
1437 : : "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1438 : : "ExecReload", "ExecStop", "ExecStopPost"))
1439 : 0 : return bus_append_exec_command(m, field, eq);
1440 : :
1441 [ # # ]: 0 : if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1442 : 0 : _cleanup_free_ int *status = NULL, *signal = NULL;
1443 : 0 : size_t n_status = 0, n_signal = 0;
1444 : : const char *p;
1445 : :
1446 : 0 : for (p = eq;;) {
1447 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
1448 : :
1449 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1450 [ # # ]: 0 : if (r == 0)
1451 : 0 : break;
1452 [ # # ]: 0 : if (r == -ENOMEM)
1453 : 0 : return log_oom();
1454 [ # # ]: 0 : if (r < 0)
1455 [ # # ]: 0 : return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
1456 : :
1457 : : /* We need to call exit_status_from_string() first, because we want
1458 : : * to parse numbers as exit statuses, not signals. */
1459 : :
1460 : 0 : r = exit_status_from_string(word);
1461 [ # # ]: 0 : if (r >= 0) {
1462 [ # # # # ]: 0 : assert(r >= 0 && r < 256);
1463 : :
1464 : 0 : status = reallocarray(status, n_status + 1, sizeof(int));
1465 [ # # ]: 0 : if (!status)
1466 : 0 : return log_oom();
1467 : :
1468 : 0 : status[n_status++] = r;
1469 : :
1470 [ # # ]: 0 : } else if ((r = signal_from_string(word)) >= 0) {
1471 : 0 : signal = reallocarray(signal, n_signal + 1, sizeof(int));
1472 [ # # ]: 0 : if (!signal)
1473 : 0 : return log_oom();
1474 : :
1475 : 0 : signal[n_signal++] = r;
1476 : :
1477 : : } else
1478 : : /* original r from exit_status_to_string() */
1479 [ # # ]: 0 : return log_error_errno(r, "Invalid status or signal %s in %s: %m",
1480 : : word, field);
1481 : : }
1482 : :
1483 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1484 [ # # ]: 0 : if (r < 0)
1485 [ # # ]: 0 : return bus_log_create_error(r);
1486 : :
1487 : 0 : r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1488 [ # # ]: 0 : if (r < 0)
1489 [ # # ]: 0 : return bus_log_create_error(r);
1490 : :
1491 : 0 : r = sd_bus_message_open_container(m, 'v', "(aiai)");
1492 [ # # ]: 0 : if (r < 0)
1493 [ # # ]: 0 : return bus_log_create_error(r);
1494 : :
1495 : 0 : r = sd_bus_message_open_container(m, 'r', "aiai");
1496 [ # # ]: 0 : if (r < 0)
1497 [ # # ]: 0 : return bus_log_create_error(r);
1498 : :
1499 : 0 : r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
1500 [ # # ]: 0 : if (r < 0)
1501 [ # # ]: 0 : return bus_log_create_error(r);
1502 : :
1503 : 0 : r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
1504 [ # # ]: 0 : if (r < 0)
1505 [ # # ]: 0 : return bus_log_create_error(r);
1506 : :
1507 : 0 : r = sd_bus_message_close_container(m);
1508 [ # # ]: 0 : if (r < 0)
1509 [ # # ]: 0 : return bus_log_create_error(r);
1510 : :
1511 : 0 : r = sd_bus_message_close_container(m);
1512 [ # # ]: 0 : if (r < 0)
1513 [ # # ]: 0 : return bus_log_create_error(r);
1514 : :
1515 : 0 : r = sd_bus_message_close_container(m);
1516 [ # # ]: 0 : if (r < 0)
1517 [ # # ]: 0 : return bus_log_create_error(r);
1518 : :
1519 : 0 : return 1;
1520 : : }
1521 : :
1522 : 0 : return 0;
1523 : : }
1524 : :
1525 : 0 : static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1526 : : int r;
1527 : :
1528 [ # # ]: 0 : if (STR_IN_SET(field,
1529 : : "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1530 : : "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1531 : :
1532 : 0 : return bus_append_parse_boolean(m, field, eq);
1533 : :
1534 [ # # ]: 0 : if (STR_IN_SET(field, "Priority", "IPTTL", "Mark"))
1535 : :
1536 : 0 : return bus_append_safe_atoi(m, field, eq);
1537 : :
1538 [ # # ]: 0 : if (streq(field, "IPTOS"))
1539 : :
1540 : 0 : return bus_append_ip_tos_from_string(m, field, eq);
1541 : :
1542 [ # # ]: 0 : if (STR_IN_SET(field, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1543 : :
1544 : 0 : return bus_append_safe_atou(m, field, eq);
1545 : :
1546 [ # # ]: 0 : if (STR_IN_SET(field, "SocketMode", "DirectoryMode"))
1547 : :
1548 : 0 : return bus_append_parse_mode(m, field, eq);
1549 : :
1550 [ # # ]: 0 : if (STR_IN_SET(field, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1551 : :
1552 : 0 : return bus_append_safe_atoi64(m, field, eq);
1553 : :
1554 [ # # ]: 0 : if (STR_IN_SET(field, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1555 : :
1556 : 0 : return bus_append_parse_sec_rename(m, field, eq);
1557 : :
1558 [ # # ]: 0 : if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1559 : :
1560 : 0 : return bus_append_parse_size(m, field, eq, 1024);
1561 : :
1562 [ # # ]: 0 : if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1563 : :
1564 : 0 : return bus_append_exec_command(m, field, eq);
1565 : :
1566 [ # # ]: 0 : if (STR_IN_SET(field,
1567 : : "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1568 : : "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1569 : : "SocketUser", "SocketGroup"))
1570 : :
1571 : 0 : return bus_append_string(m, field, eq);
1572 : :
1573 [ # # ]: 0 : if (streq(field, "Symlinks"))
1574 : :
1575 : 0 : return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
1576 : :
1577 [ # # ]: 0 : if (streq(field, "SocketProtocol"))
1578 : :
1579 : 0 : return bus_append_parse_ip_protocol(m, field, eq);
1580 : :
1581 [ # # ]: 0 : if (STR_IN_SET(field,
1582 : : "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1583 : : "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1584 : :
1585 [ # # ]: 0 : if (isempty(eq))
1586 : 0 : r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
1587 : : else
1588 : 0 : r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
1589 [ # # ]: 0 : if (r < 0)
1590 [ # # ]: 0 : return bus_log_create_error(r);
1591 : :
1592 : 0 : return 1;
1593 : : }
1594 : :
1595 : 0 : return 0;
1596 : : }
1597 : 0 : static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
1598 : : int r;
1599 : :
1600 [ # # ]: 0 : if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
1601 : : "OnTimezoneChange", "OnClockChange"))
1602 : :
1603 : 0 : return bus_append_parse_boolean(m, field, eq);
1604 : :
1605 [ # # ]: 0 : if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec"))
1606 : :
1607 : 0 : return bus_append_parse_sec_rename(m, field, eq);
1608 : :
1609 [ # # ]: 0 : if (STR_IN_SET(field,
1610 : : "OnActiveSec", "OnBootSec", "OnStartupSec",
1611 : : "OnUnitActiveSec","OnUnitInactiveSec")) {
1612 : :
1613 [ # # ]: 0 : if (isempty(eq))
1614 : 0 : r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1615 : : else {
1616 : : usec_t t;
1617 : 0 : r = parse_sec(eq, &t);
1618 [ # # ]: 0 : if (r < 0)
1619 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
1620 : :
1621 : 0 : r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1622 : : }
1623 [ # # ]: 0 : if (r < 0)
1624 [ # # ]: 0 : return bus_log_create_error(r);
1625 : :
1626 : 0 : return 1;
1627 : : }
1628 : :
1629 [ # # ]: 0 : if (streq(field, "OnCalendar")) {
1630 : :
1631 [ # # ]: 0 : if (isempty(eq))
1632 : 0 : r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1633 : : else
1634 : 0 : r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1635 [ # # ]: 0 : if (r < 0)
1636 [ # # ]: 0 : return bus_log_create_error(r);
1637 : :
1638 : 0 : return 1;
1639 : : }
1640 : :
1641 : 0 : return 0;
1642 : : }
1643 : :
1644 : 0 : static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
1645 : 0 : ConditionType t = _CONDITION_TYPE_INVALID;
1646 : 0 : bool is_condition = false;
1647 : : int r;
1648 : :
1649 [ # # ]: 0 : if (STR_IN_SET(field,
1650 : : "Description", "SourcePath", "OnFailureJobMode",
1651 : : "JobTimeoutAction", "JobTimeoutRebootArgument",
1652 : : "StartLimitAction", "FailureAction", "SuccessAction",
1653 : : "RebootArgument", "CollectMode"))
1654 : :
1655 : 0 : return bus_append_string(m, field, eq);
1656 : :
1657 [ # # ]: 0 : if (STR_IN_SET(field,
1658 : : "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1659 : : "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1660 : :
1661 : 0 : return bus_append_parse_boolean(m, field, eq);
1662 : :
1663 [ # # ]: 0 : if (STR_IN_SET(field, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1664 : :
1665 : 0 : return bus_append_parse_sec_rename(m, field, eq);
1666 : :
1667 [ # # ]: 0 : if (streq(field, "StartLimitBurst"))
1668 : :
1669 : 0 : return bus_append_safe_atou(m, field, eq);
1670 : :
1671 [ # # ]: 0 : if (STR_IN_SET(field, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1672 : :
1673 [ # # ]: 0 : if (isempty(eq))
1674 : 0 : r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1675 : : else {
1676 : : uint8_t u;
1677 : :
1678 : 0 : r = safe_atou8(eq, &u);
1679 [ # # ]: 0 : if (r < 0)
1680 [ # # ]: 0 : return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1681 : :
1682 : 0 : r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1683 : : }
1684 [ # # ]: 0 : if (r < 0)
1685 [ # # ]: 0 : return bus_log_create_error(r);
1686 : :
1687 : 0 : return 1;
1688 : : }
1689 : :
1690 [ # # ]: 0 : if (unit_dependency_from_string(field) >= 0 ||
1691 [ # # ]: 0 : STR_IN_SET(field, "Documentation", "RequiresMountsFor"))
1692 : :
1693 : 0 : return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
1694 : :
1695 : 0 : t = condition_type_from_string(field);
1696 [ # # ]: 0 : if (t >= 0)
1697 : 0 : is_condition = true;
1698 : : else
1699 : 0 : t = assert_type_from_string(field);
1700 [ # # ]: 0 : if (t >= 0) {
1701 [ # # ]: 0 : if (isempty(eq))
1702 [ # # ]: 0 : r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1703 : : else {
1704 : 0 : const char *p = eq;
1705 : : int trigger, negate;
1706 : :
1707 : 0 : trigger = *p == '|';
1708 [ # # ]: 0 : if (trigger)
1709 : 0 : p++;
1710 : :
1711 : 0 : negate = *p == '!';
1712 [ # # ]: 0 : if (negate)
1713 : 0 : p++;
1714 : :
1715 [ # # ]: 0 : r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1716 : : field, trigger, negate, p);
1717 : : }
1718 [ # # ]: 0 : if (r < 0)
1719 [ # # ]: 0 : return bus_log_create_error(r);
1720 : :
1721 : 0 : return 1;
1722 : : }
1723 : :
1724 : 0 : return 0;
1725 : : }
1726 : :
1727 : 0 : int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1728 : : const char *eq, *field;
1729 : : int r;
1730 : :
1731 [ # # ]: 0 : assert(m);
1732 [ # # ]: 0 : assert(assignment);
1733 : :
1734 : 0 : eq = strchr(assignment, '=');
1735 [ # # ]: 0 : if (!eq)
1736 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1737 : : "Not an assignment: %s", assignment);
1738 : :
1739 : 0 : field = strndupa(assignment, eq - assignment);
1740 : 0 : eq++;
1741 : :
1742 [ # # # # : 0 : switch (t) {
# # # # #
# ]
1743 : 0 : case UNIT_SERVICE:
1744 : 0 : r = bus_append_cgroup_property(m, field, eq);
1745 [ # # ]: 0 : if (r != 0)
1746 : 0 : return r;
1747 : :
1748 : 0 : r = bus_append_execute_property(m, field, eq);
1749 [ # # ]: 0 : if (r != 0)
1750 : 0 : return r;
1751 : :
1752 : 0 : r = bus_append_kill_property(m, field, eq);
1753 [ # # ]: 0 : if (r != 0)
1754 : 0 : return r;
1755 : :
1756 : 0 : r = bus_append_service_property(m, field, eq);
1757 [ # # ]: 0 : if (r != 0)
1758 : 0 : return r;
1759 : 0 : break;
1760 : :
1761 : 0 : case UNIT_SOCKET:
1762 : 0 : r = bus_append_cgroup_property(m, field, eq);
1763 [ # # ]: 0 : if (r != 0)
1764 : 0 : return r;
1765 : :
1766 : 0 : r = bus_append_execute_property(m, field, eq);
1767 [ # # ]: 0 : if (r != 0)
1768 : 0 : return r;
1769 : :
1770 : 0 : r = bus_append_kill_property(m, field, eq);
1771 [ # # ]: 0 : if (r != 0)
1772 : 0 : return r;
1773 : :
1774 : 0 : r = bus_append_socket_property(m, field, eq);
1775 [ # # ]: 0 : if (r != 0)
1776 : 0 : return r;
1777 : 0 : break;
1778 : :
1779 : 0 : case UNIT_TIMER:
1780 : 0 : r = bus_append_timer_property(m, field, eq);
1781 [ # # ]: 0 : if (r != 0)
1782 : 0 : return r;
1783 : 0 : break;
1784 : :
1785 : 0 : case UNIT_PATH:
1786 : 0 : r = bus_append_path_property(m, field, eq);
1787 [ # # ]: 0 : if (r != 0)
1788 : 0 : return r;
1789 : 0 : break;
1790 : :
1791 : 0 : case UNIT_SLICE:
1792 : 0 : r = bus_append_cgroup_property(m, field, eq);
1793 [ # # ]: 0 : if (r != 0)
1794 : 0 : return r;
1795 : 0 : break;
1796 : :
1797 : 0 : case UNIT_SCOPE:
1798 : :
1799 [ # # ]: 0 : if (streq(field, "TimeoutStopSec"))
1800 : 0 : return bus_append_parse_sec_rename(m, field, eq);
1801 : :
1802 : 0 : r = bus_append_cgroup_property(m, field, eq);
1803 [ # # ]: 0 : if (r != 0)
1804 : 0 : return r;
1805 : :
1806 : 0 : r = bus_append_kill_property(m, field, eq);
1807 [ # # ]: 0 : if (r != 0)
1808 : 0 : return r;
1809 : 0 : break;
1810 : :
1811 : 0 : case UNIT_MOUNT:
1812 : 0 : r = bus_append_cgroup_property(m, field, eq);
1813 [ # # ]: 0 : if (r != 0)
1814 : 0 : return r;
1815 : :
1816 : 0 : r = bus_append_execute_property(m, field, eq);
1817 [ # # ]: 0 : if (r != 0)
1818 : 0 : return r;
1819 : :
1820 : 0 : r = bus_append_kill_property(m, field, eq);
1821 [ # # ]: 0 : if (r != 0)
1822 : 0 : return r;
1823 : :
1824 : 0 : r = bus_append_mount_property(m, field, eq);
1825 [ # # ]: 0 : if (r != 0)
1826 : 0 : return r;
1827 : :
1828 : 0 : break;
1829 : :
1830 : 0 : case UNIT_AUTOMOUNT:
1831 : 0 : r = bus_append_automount_property(m, field, eq);
1832 [ # # ]: 0 : if (r != 0)
1833 : 0 : return r;
1834 : :
1835 : 0 : break;
1836 : :
1837 : 0 : case UNIT_TARGET:
1838 : : case UNIT_DEVICE:
1839 : : case UNIT_SWAP:
1840 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1841 : : "Not supported unit type");
1842 : :
1843 : 0 : default:
1844 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1845 : : "Invalid unit type");
1846 : : }
1847 : :
1848 : 0 : r = bus_append_unit_property(m, field, eq);
1849 [ # # ]: 0 : if (r != 0)
1850 : 0 : return r;
1851 : :
1852 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1853 : : "Unknown assignment: %s", assignment);
1854 : : }
1855 : :
1856 : 0 : int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
1857 : : char **i;
1858 : : int r;
1859 : :
1860 [ # # ]: 0 : assert(m);
1861 : :
1862 [ # # # # ]: 0 : STRV_FOREACH(i, l) {
1863 : 0 : r = bus_append_unit_property_assignment(m, t, *i);
1864 [ # # ]: 0 : if (r < 0)
1865 : 0 : return r;
1866 : : }
1867 : :
1868 : 0 : return 0;
1869 : : }
1870 : :
1871 : 0 : int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
1872 : : const char *type, *path, *source;
1873 : : int r;
1874 : :
1875 : : /* changes is dereferenced when calling unit_file_dump_changes() later,
1876 : : * so we have to make sure this is not NULL. */
1877 [ # # ]: 0 : assert(changes);
1878 [ # # ]: 0 : assert(n_changes);
1879 : :
1880 : 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1881 [ # # ]: 0 : if (r < 0)
1882 [ # # ]: 0 : return bus_log_parse_error(r);
1883 : :
1884 [ # # ]: 0 : while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1885 : : /* We expect only "success" changes to be sent over the bus.
1886 : : Hence, reject anything negative. */
1887 : 0 : UnitFileChangeType ch = unit_file_change_type_from_string(type);
1888 : :
1889 [ # # ]: 0 : if (ch < 0) {
1890 [ # # ]: 0 : log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
1891 : 0 : continue;
1892 : : }
1893 : :
1894 : 0 : r = unit_file_changes_add(changes, n_changes, ch, path, source);
1895 [ # # ]: 0 : if (r < 0)
1896 : 0 : return r;
1897 : : }
1898 [ # # ]: 0 : if (r < 0)
1899 [ # # ]: 0 : return bus_log_parse_error(r);
1900 : :
1901 : 0 : r = sd_bus_message_exit_container(m);
1902 [ # # ]: 0 : if (r < 0)
1903 [ # # ]: 0 : return bus_log_parse_error(r);
1904 : :
1905 : 0 : unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
1906 : 0 : return 0;
1907 : : }
1908 : :
1909 : 0 : int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
1910 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1911 : 0 : _cleanup_free_ char *path = NULL;
1912 : : int r;
1913 : :
1914 : 0 : path = unit_dbus_path_from_name(name);
1915 [ # # ]: 0 : if (!path)
1916 : 0 : return log_oom();
1917 : :
1918 : : /* This function warns on it's own, because otherwise it'd be awkward to pass
1919 : : * the dbus error message around. */
1920 : :
1921 : 0 : r = sd_bus_get_property_string(
1922 : : bus,
1923 : : "org.freedesktop.systemd1",
1924 : : path,
1925 : : "org.freedesktop.systemd1.Unit",
1926 : : "LoadState",
1927 : : &error,
1928 : : load_state);
1929 [ # # ]: 0 : if (r < 0)
1930 [ # # ]: 0 : return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
1931 : :
1932 : 0 : return 0;
1933 : : }
|