]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
e51646a29468b6a4a5e6ea427492ba4c3c4beb2f
[thirdparty/systemd.git] / src / shared / bus-unit-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <paths.h>
4 #include <sys/mount.h>
5
6 #include "sd-bus.h"
7
8 #include "alloc-util.h"
9 #include "bus-common-errors.h"
10 #include "bus-error.h"
11 #include "bus-locator.h"
12 #include "bus-unit-util.h"
13 #include "bus-util.h"
14 #include "cap-list.h"
15 #include "cgroup-setup.h"
16 #include "cgroup-util.h"
17 #include "condition.h"
18 #include "constants.h"
19 #include "coredump-util.h"
20 #include "cpu-set-util.h"
21 #include "escape.h"
22 #include "exec-util.h"
23 #include "exit-status.h"
24 #include "extract-word.h"
25 #include "firewall-util.h"
26 #include "hexdecoct.h"
27 #include "hostname-util.h"
28 #include "in-addr-util.h"
29 #include "install.h"
30 #include "ioprio-util.h"
31 #include "ip-protocol-list.h"
32 #include "log.h"
33 #include "mountpoint-util.h"
34 #include "nsflags.h"
35 #include "numa-util.h"
36 #include "open-file.h"
37 #include "parse-helpers.h"
38 #include "parse-util.h"
39 #include "path-util.h"
40 #include "percent-util.h"
41 #include "pidref.h"
42 #include "process-util.h"
43 #include "rlimit-util.h"
44 #include "seccomp-util.h"
45 #include "securebits-util.h"
46 #include "signal-util.h"
47 #include "socket-util.h"
48 #include "string-util.h"
49 #include "syslog-util.h"
50 #include "time-util.h"
51 #include "unit-def.h"
52
53 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
54 assert(message);
55 assert(u);
56
57 u->machine = NULL;
58
59 return sd_bus_message_read(
60 message,
61 "(ssssssouso)",
62 &u->id,
63 &u->description,
64 &u->load_state,
65 &u->active_state,
66 &u->sub_state,
67 &u->following,
68 &u->unit_path,
69 &u->job_id,
70 &u->job_type,
71 &u->job_path);
72 }
73
74 static int warn_deprecated(const char *field, const char *eq) {
75 log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field, field, eq);
76 return 1;
77 }
78
79 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
80 static int bus_append_##parse_func( \
81 sd_bus_message *m, \
82 const char *field, \
83 const char *eq) { \
84 type val; \
85 int r; \
86 \
87 r = parse_func(eq, &val); \
88 if (r < 0) \
89 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
90 \
91 r = sd_bus_message_append(m, "(sv)", field, \
92 bus_type, (cast_type) val); \
93 if (r < 0) \
94 return bus_log_create_error(r); \
95 \
96 return 1; \
97 }
98
99 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
100 static int bus_append_##parse_func( \
101 sd_bus_message *m, \
102 const char *field, \
103 const char *eq) { \
104 int r; \
105 \
106 r = parse_func(eq); \
107 if (r < 0) \
108 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
109 \
110 r = sd_bus_message_append(m, "(sv)", field, \
111 bus_type, (int32_t) r); \
112 if (r < 0) \
113 return bus_log_create_error(r); \
114 \
115 return 1; \
116 }
117
118 DEFINE_BUS_APPEND_PARSE("b", parse_boolean);
119 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
120 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
121 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
122 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
123 DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action);
124 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
125 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
126 DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
127 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
128 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
129 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
130 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
131 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse);
134 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string);
135 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
136 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
137 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
138 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
139 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string);
140
141 static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
142 int r;
143
144 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
145 if (r < 0)
146 return bus_log_create_error(r);
147
148 return 1;
149 }
150
151 static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) {
152 int r;
153
154 assert(m);
155 assert(field);
156
157 r = sd_bus_message_open_container(m, 'r', "sv");
158 if (r < 0)
159 return bus_log_create_error(r);
160
161 r = sd_bus_message_append_basic(m, 's', field);
162 if (r < 0)
163 return bus_log_create_error(r);
164
165 r = sd_bus_message_open_container(m, 'v', "as");
166 if (r < 0)
167 return bus_log_create_error(r);
168
169 r = sd_bus_message_open_container(m, 'a', "s");
170 if (r < 0)
171 return bus_log_create_error(r);
172
173 for (const char *p = eq;;) {
174 _cleanup_free_ char *word = NULL;
175
176 r = extract_first_word(&p, &word, separator, flags);
177 if (r == -ENOMEM)
178 return log_oom();
179 if (r < 0)
180 return log_error_errno(r, "Invalid syntax: %s", eq);
181 if (r == 0)
182 break;
183
184 r = sd_bus_message_append_basic(m, 's', word);
185 if (r < 0)
186 return bus_log_create_error(r);
187 }
188
189 r = sd_bus_message_close_container(m);
190 if (r < 0)
191 return bus_log_create_error(r);
192
193 r = sd_bus_message_close_container(m);
194 if (r < 0)
195 return bus_log_create_error(r);
196
197 r = sd_bus_message_close_container(m);
198 if (r < 0)
199 return bus_log_create_error(r);
200
201 return 1;
202 }
203
204 static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
205 int r;
206
207 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
208 if (r < 0)
209 return bus_log_create_error(r);
210
211 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
212 if (r < 0)
213 return bus_log_create_error(r);
214
215 r = sd_bus_message_open_container(m, 'v', "ay");
216 if (r < 0)
217 return bus_log_create_error(r);
218
219 r = sd_bus_message_append_array(m, 'y', buf, n);
220 if (r < 0)
221 return bus_log_create_error(r);
222
223 r = sd_bus_message_close_container(m);
224 if (r < 0)
225 return bus_log_create_error(r);
226
227 r = sd_bus_message_close_container(m);
228 if (r < 0)
229 return bus_log_create_error(r);
230
231 return 1;
232 }
233
234 static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
235 char *n;
236 usec_t t;
237 size_t l;
238 int r;
239
240 r = parse_sec(eq, &t);
241 if (r < 0)
242 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
243
244 l = strlen(field);
245 n = newa(char, l + 2);
246 /* Change suffix Sec → USec */
247 strcpy(mempcpy(n, field, l - 3), "USec");
248
249 r = sd_bus_message_append(m, "(sv)", n, "t", t);
250 if (r < 0)
251 return bus_log_create_error(r);
252
253 return 1;
254 }
255
256 static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
257 uint64_t v;
258 int r;
259
260 r = parse_size(eq, base, &v);
261 if (r < 0)
262 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
263
264 r = sd_bus_message_append(m, "(sv)", field, "t", v);
265 if (r < 0)
266 return bus_log_create_error(r);
267
268 return 1;
269 }
270
271 static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
272 bool explicit_path = false, done = false, ambient_hack = false;
273 _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
274 _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
275 ExecCommandFlags flags = 0;
276 bool is_ex_prop = endswith(field, "Ex");
277 int r;
278
279 do {
280 switch (*eq) {
281
282 case '-':
283 if (FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE))
284 done = true;
285 else {
286 flags |= EXEC_COMMAND_IGNORE_FAILURE;
287 eq++;
288 }
289 break;
290
291 case '@':
292 if (explicit_path)
293 done = true;
294 else {
295 explicit_path = true;
296 eq++;
297 }
298 break;
299
300 case ':':
301 if (FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND))
302 done = true;
303 else {
304 flags |= EXEC_COMMAND_NO_ENV_EXPAND;
305 eq++;
306 }
307 break;
308
309 case '+':
310 if ((flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID)) != 0 || ambient_hack)
311 done = true;
312 else {
313 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
314 eq++;
315 }
316 break;
317
318 case '!':
319 if (FLAGS_SET(flags, EXEC_COMMAND_FULLY_PRIVILEGED) || ambient_hack)
320 done = true;
321 else if (FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)) {
322 /* Compatibility with the old !! ambient caps hack (removed in v258). Since
323 * we don't support that anymore and !! was a noop on non-supporting systems,
324 * we'll just turn off the EXEC_COMMAND_NO_SETUID flag again and be done with
325 * it. */
326 flags &= ~EXEC_COMMAND_NO_SETUID;
327 eq++;
328 ambient_hack = true;
329
330 log_notice("!! modifier for %s= fields is no longer supported and is now ignored.", field);
331 } else {
332 flags |= EXEC_COMMAND_NO_SETUID;
333 eq++;
334 }
335 break;
336
337 case '|':
338 if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL))
339 done = true;
340 else {
341 flags |= EXEC_COMMAND_VIA_SHELL;
342 eq++;
343 }
344 break;
345
346 default:
347 done = true;
348 }
349 } while (!done);
350
351 if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_VIA_SHELL))) {
352 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
353 is_ex_prop = true;
354
355 upgraded_name = strjoin(field, "Ex");
356 if (!upgraded_name)
357 return log_oom();
358 field = upgraded_name;
359 }
360
361 if (is_ex_prop) {
362 r = exec_command_flags_to_strv(flags, &ex_opts);
363 if (r < 0)
364 return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
365 }
366
367 if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
368 path = strdup(_PATH_BSHELL);
369 if (!path)
370 return log_oom();
371
372 } else if (explicit_path) {
373 r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
374 if (r < 0)
375 return log_error_errno(r, "Failed to parse path: %m");
376 if (r == 0)
377 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No executable path specified, refusing.");
378 if (isempty(eq))
379 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got empty command line, refusing.");
380 }
381
382 r = strv_split_full(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
383 if (r < 0)
384 return log_error_errno(r, "Failed to parse command line: %m");
385
386 if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
387 r = strv_prepend(&l, explicit_path ? "-sh" : "sh");
388 if (r < 0)
389 return log_oom();
390 }
391
392 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
393 if (r < 0)
394 return bus_log_create_error(r);
395
396 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
397 if (r < 0)
398 return bus_log_create_error(r);
399
400 r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
401 if (r < 0)
402 return bus_log_create_error(r);
403
404 r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
405 if (r < 0)
406 return bus_log_create_error(r);
407
408 if (!strv_isempty(l)) {
409
410 r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
411 if (r < 0)
412 return bus_log_create_error(r);
413
414 r = sd_bus_message_append(m, "s", path ?: l[0]);
415 if (r < 0)
416 return bus_log_create_error(r);
417
418 r = sd_bus_message_append_strv(m, l);
419 if (r < 0)
420 return bus_log_create_error(r);
421
422 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));
423 if (r < 0)
424 return bus_log_create_error(r);
425
426 r = sd_bus_message_close_container(m);
427 if (r < 0)
428 return bus_log_create_error(r);
429 }
430
431 r = sd_bus_message_close_container(m);
432 if (r < 0)
433 return bus_log_create_error(r);
434
435 r = sd_bus_message_close_container(m);
436 if (r < 0)
437 return bus_log_create_error(r);
438
439 r = sd_bus_message_close_container(m);
440 if (r < 0)
441 return bus_log_create_error(r);
442
443 return 1;
444 }
445
446 static int bus_append_open_file(sd_bus_message *m, const char *field, const char *eq) {
447 _cleanup_(open_file_freep) OpenFile *of = NULL;
448 int r;
449
450 assert(m);
451
452 r = open_file_parse(eq, &of);
453 if (r < 0)
454 return log_error_errno(r, "Failed to parse OpenFile= setting: %m");
455
456 r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags);
457 if (r < 0)
458 return bus_log_create_error(r);
459
460 return 1;
461 }
462
463 static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
464 int r;
465
466 assert(m);
467 assert(prefix);
468
469 r = sd_bus_message_open_container(m, 'r', "iayu");
470 if (r < 0)
471 return r;
472
473 r = sd_bus_message_append(m, "i", family);
474 if (r < 0)
475 return r;
476
477 r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
478 if (r < 0)
479 return r;
480
481 r = sd_bus_message_append(m, "u", prefixlen);
482 if (r < 0)
483 return r;
484
485 return sd_bus_message_close_container(m);
486 }
487
488 static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
489 int r;
490
491 assert(m);
492 assert(field);
493 assert(eq);
494
495 if (isempty(eq)) {
496 r = sd_bus_message_append(m, "(sv)", field, "a(iiss)", 0);
497 if (r < 0)
498 return bus_log_create_error(r);
499
500 return 1;
501 }
502
503 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
504 if (r < 0)
505 return bus_log_create_error(r);
506
507 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
508 if (r < 0)
509 return bus_log_create_error(r);
510
511 r = sd_bus_message_open_container(m, 'v', "a(iiss)");
512 if (r < 0)
513 return bus_log_create_error(r);
514
515 r = sd_bus_message_open_container(m, 'a', "(iiss)");
516 if (r < 0)
517 return bus_log_create_error(r);
518
519 for (const char *p = eq;;) {
520 _cleanup_free_ char *tuple = NULL, *source_str = NULL, *nfproto_str = NULL, *table = NULL, *set = NULL;
521 const char *q = NULL;
522 int source, nfproto;
523
524 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
525 if (r == -ENOMEM)
526 return log_oom();
527 if (r < 0)
528 return log_error_errno(r, "Failed to parse %s: %m", field);
529 if (r == 0)
530 break;
531 if (isempty(tuple))
532 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
533
534 q = tuple;
535 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
536 if (r == -ENOMEM)
537 return log_oom();
538 if (r != 4 || !isempty(q))
539 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
540
541 assert(source_str);
542 assert(nfproto_str);
543 assert(table);
544 assert(set);
545
546 source = nft_set_source_from_string(source_str);
547 if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
548 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
549
550 nfproto = nfproto_from_string(nfproto_str);
551 if (nfproto < 0 || !nft_identifier_valid(table) || !nft_identifier_valid(set))
552 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
553
554 r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set);
555 if (r < 0)
556 return bus_log_create_error(r);
557 }
558 r = sd_bus_message_close_container(m);
559 if (r < 0)
560 return bus_log_create_error(r);
561
562 r = sd_bus_message_close_container(m);
563 if (r < 0)
564 return bus_log_create_error(r);
565
566 r = sd_bus_message_close_container(m);
567 if (r < 0)
568 return bus_log_create_error(r);
569
570 return 1;
571 }
572
573 static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
574 int r;
575
576 if (STR_IN_SET(field, "DevicePolicy",
577 "Slice",
578 "ManagedOOMSwap",
579 "ManagedOOMMemoryPressure",
580 "ManagedOOMPreference",
581 "MemoryPressureWatch",
582 "DelegateSubgroup"))
583 return bus_append_string(m, field, eq);
584
585 if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
586 r = parse_permyriad(eq);
587 if (r < 0)
588 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
589
590 /* Pass around scaled to 2^32-1 == 100% */
591 r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
592 if (r < 0)
593 return bus_log_create_error(r);
594
595 return 1;
596 }
597
598 if (STR_IN_SET(field, "MemoryAccounting",
599 "MemoryZSwapWriteback",
600 "IOAccounting",
601 "TasksAccounting",
602 "IPAccounting",
603 "CoredumpReceive"))
604 return bus_append_parse_boolean(m, field, eq);
605
606 if (STR_IN_SET(field, "CPUWeight",
607 "StartupCPUWeight"))
608 return bus_append_cg_cpu_weight_parse(m, field, eq);
609
610 if (STR_IN_SET(field, "IOWeight",
611 "StartupIOWeight"))
612 return bus_append_cg_weight_parse(m, field, eq);
613
614 if (STR_IN_SET(field, "AllowedCPUs",
615 "StartupAllowedCPUs",
616 "AllowedMemoryNodes",
617 "StartupAllowedMemoryNodes")) {
618
619 _cleanup_(cpu_set_done) CPUSet cpuset = {};
620 _cleanup_free_ uint8_t *array = NULL;
621 size_t allocated;
622
623 r = parse_cpu_set(eq, &cpuset);
624 if (r < 0)
625 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
626
627 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
628 if (r < 0)
629 return log_error_errno(r, "Failed to serialize CPUSet: %m");
630
631 return bus_append_byte_array(m, field, array, allocated);
632 }
633
634 if (streq(field, "DisableControllers"))
635 return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
636
637 if (streq(field, "Delegate")) {
638 r = parse_boolean(eq);
639 if (r < 0)
640 return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
641
642 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
643 if (r < 0)
644 return bus_log_create_error(r);
645
646 return 1;
647 }
648
649 if (STR_IN_SET(field, "MemoryMin",
650 "DefaultMemoryLow",
651 "DefaultMemoryMin",
652 "MemoryLow",
653 "MemoryHigh",
654 "MemoryMax",
655 "MemorySwapMax",
656 "MemoryZSwapMax",
657 "TasksMax")) {
658
659 if (streq(eq, "infinity")) {
660 r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
661 if (r < 0)
662 return bus_log_create_error(r);
663 return 1;
664 } else if (isempty(eq)) {
665 uint64_t empty_value = STR_IN_SET(field,
666 "DefaultMemoryLow",
667 "DefaultMemoryMin",
668 "MemoryLow",
669 "MemoryMin") ?
670 CGROUP_LIMIT_MIN :
671 CGROUP_LIMIT_MAX;
672
673 r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
674 if (r < 0)
675 return bus_log_create_error(r);
676 return 1;
677 }
678
679 r = parse_permyriad(eq);
680 if (r >= 0) {
681 char *n;
682
683 /* When this is a percentage we'll convert this into a relative value in the range
684 * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related ones). This
685 * way the physical memory size can be determined server-side. */
686
687 n = strjoina(field, "Scale");
688 r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
689 if (r < 0)
690 return bus_log_create_error(r);
691
692 return 1;
693 }
694
695 if (streq(field, "TasksMax"))
696 return bus_append_safe_atou64(m, field, eq);
697
698 return bus_append_parse_size(m, field, eq, 1024);
699 }
700
701 if (streq(field, "CPUQuota")) {
702 if (isempty(eq))
703 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
704 else {
705 r = parse_permyriad_unbounded(eq);
706 if (r == 0)
707 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "CPU quota too small.");
708 if (r < 0)
709 return log_error_errno(r, "CPU quota '%s' invalid.", eq);
710
711 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
712 }
713
714 if (r < 0)
715 return bus_log_create_error(r);
716
717 return 1;
718 }
719
720 if (streq(field, "CPUQuotaPeriodSec")) {
721 usec_t u = USEC_INFINITY;
722
723 r = parse_sec_def_infinity(eq, &u);
724 if (r < 0)
725 return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
726
727 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
728 if (r < 0)
729 return bus_log_create_error(r);
730
731 return 1;
732 }
733
734 if (streq(field, "DeviceAllow")) {
735 if (isempty(eq))
736 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
737 else {
738 const char *path = eq, *rwm = NULL, *e;
739
740 e = strchr(eq, ' ');
741 if (e) {
742 path = strndupa_safe(eq, e - eq);
743 rwm = e+1;
744 }
745
746 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
747 }
748
749 if (r < 0)
750 return bus_log_create_error(r);
751
752 return 1;
753 }
754
755 if (cgroup_io_limit_type_from_string(field) >= 0) {
756
757 if (isempty(eq))
758 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
759 else {
760 const char *path, *bandwidth, *e;
761 uint64_t bytes;
762
763 e = strchr(eq, ' ');
764 if (!e)
765 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
766 "Failed to parse %s value %s.",
767 field, eq);
768
769 path = strndupa_safe(eq, e - eq);
770 bandwidth = e+1;
771
772 if (streq(bandwidth, "infinity"))
773 bytes = CGROUP_LIMIT_MAX;
774 else {
775 r = parse_size(bandwidth, 1000, &bytes);
776 if (r < 0)
777 return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
778 }
779
780 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
781 }
782
783 if (r < 0)
784 return bus_log_create_error(r);
785
786 return 1;
787 }
788
789 if (streq(field, "IODeviceWeight")) {
790 if (isempty(eq))
791 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
792 else {
793 const char *path, *weight, *e;
794 uint64_t u;
795
796 e = strchr(eq, ' ');
797 if (!e)
798 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
799 "Failed to parse %s value %s.",
800 field, eq);
801
802 path = strndupa_safe(eq, e - eq);
803 weight = e+1;
804
805 r = safe_atou64(weight, &u);
806 if (r < 0)
807 return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
808
809 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
810 }
811
812 if (r < 0)
813 return bus_log_create_error(r);
814
815 return 1;
816 }
817
818 if (streq(field, "IODeviceLatencyTargetSec")) {
819 const char *field_usec = "IODeviceLatencyTargetUSec";
820
821 if (isempty(eq))
822 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
823 else {
824 const char *path, *target, *e;
825 usec_t usec;
826
827 e = strchr(eq, ' ');
828 if (!e)
829 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
830 "Failed to parse %s value %s.",
831 field, eq);
832
833 path = strndupa_safe(eq, e - eq);
834 target = e+1;
835
836 r = parse_sec(target, &usec);
837 if (r < 0)
838 return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
839
840 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
841 }
842
843 if (r < 0)
844 return bus_log_create_error(r);
845
846 return 1;
847 }
848
849 if (STR_IN_SET(field, "IPAddressAllow",
850 "IPAddressDeny")) {
851 unsigned char prefixlen;
852 union in_addr_union prefix = {};
853 int family;
854
855 if (isempty(eq)) {
856 r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
857 if (r < 0)
858 return bus_log_create_error(r);
859
860 return 1;
861 }
862
863 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
864 if (r < 0)
865 return bus_log_create_error(r);
866
867 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
868 if (r < 0)
869 return bus_log_create_error(r);
870
871 r = sd_bus_message_open_container(m, 'v', "a(iayu)");
872 if (r < 0)
873 return bus_log_create_error(r);
874
875 r = sd_bus_message_open_container(m, 'a', "(iayu)");
876 if (r < 0)
877 return bus_log_create_error(r);
878
879 if (streq(eq, "any")) {
880 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
881
882 r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
883 if (r < 0)
884 return bus_log_create_error(r);
885
886 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
887 if (r < 0)
888 return bus_log_create_error(r);
889
890 } else if (is_localhost(eq)) {
891 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
892
893 prefix.in.s_addr = htobe32(0x7f000000);
894 r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
895 if (r < 0)
896 return bus_log_create_error(r);
897
898 prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
899 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
900 if (r < 0)
901 return r;
902
903 } else if (streq(eq, "link-local")) {
904 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
905
906 prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
907 r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
908 if (r < 0)
909 return bus_log_create_error(r);
910
911 prefix.in6 = (struct in6_addr) {
912 .s6_addr32[0] = htobe32(0xfe800000)
913 };
914 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
915 if (r < 0)
916 return bus_log_create_error(r);
917
918 } else if (streq(eq, "multicast")) {
919 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
920
921 prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
922 r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
923 if (r < 0)
924 return bus_log_create_error(r);
925
926 prefix.in6 = (struct in6_addr) {
927 .s6_addr32[0] = htobe32(0xff000000)
928 };
929 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
930 if (r < 0)
931 return bus_log_create_error(r);
932
933 } else {
934 for (;;) {
935 _cleanup_free_ char *word = NULL;
936
937 r = extract_first_word(&eq, &word, NULL, 0);
938 if (r == 0)
939 break;
940 if (r == -ENOMEM)
941 return log_oom();
942 if (r < 0)
943 return log_error_errno(r, "Failed to parse %s: %s", field, eq);
944
945 r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
946 if (r < 0)
947 return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
948
949 r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
950 if (r < 0)
951 return bus_log_create_error(r);
952 }
953 }
954
955 r = sd_bus_message_close_container(m);
956 if (r < 0)
957 return bus_log_create_error(r);
958
959 r = sd_bus_message_close_container(m);
960 if (r < 0)
961 return bus_log_create_error(r);
962
963 r = sd_bus_message_close_container(m);
964 if (r < 0)
965 return bus_log_create_error(r);
966
967 return 1;
968 }
969
970 if (STR_IN_SET(field, "IPIngressFilterPath",
971 "IPEgressFilterPath")) {
972 if (isempty(eq))
973 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
974 else
975 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
976
977 if (r < 0)
978 return bus_log_create_error(r);
979
980 return 1;
981 }
982
983 if (streq(field, "BPFProgram")) {
984 if (isempty(eq))
985 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
986 else {
987 _cleanup_free_ char *word = NULL;
988
989 r = extract_first_word(&eq, &word, ":", 0);
990 if (r == -ENOMEM)
991 return log_oom();
992 if (r < 0)
993 return log_error_errno(r, "Failed to parse %s: %m", field);
994
995 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
996 }
997 if (r < 0)
998 return bus_log_create_error(r);
999
1000 return 1;
1001 }
1002
1003 if (STR_IN_SET(field, "SocketBindAllow",
1004 "SocketBindDeny")) {
1005 if (isempty(eq))
1006 r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
1007 else {
1008 int32_t family, ip_protocol;
1009 uint16_t nr_ports, port_min;
1010
1011 r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
1012 if (r == -ENOMEM)
1013 return log_oom();
1014 if (r < 0)
1015 return log_error_errno(r, "Failed to parse %s", field);
1016
1017 r = sd_bus_message_append(
1018 m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
1019 }
1020 if (r < 0)
1021 return bus_log_create_error(r);
1022
1023 return 1;
1024 }
1025
1026 if (streq(field, "MemoryPressureThresholdSec"))
1027 return bus_append_parse_sec_rename(m, field, eq);
1028
1029 if (streq(field, "NFTSet"))
1030 return bus_append_nft_set(m, field, eq);
1031
1032 if (streq(field, "ManagedOOMMemoryPressureDurationSec"))
1033 /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which
1034 * means use the default memory pressure duration from oomd.conf. */
1035 return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
1036
1037 if (STR_IN_SET(field,
1038 "MemoryLimit",
1039 "CPUShares",
1040 "StartupCPUShares",
1041 "BlockIOAccounting",
1042 "BlockIOWeight",
1043 "StartupBlockIOWeight",
1044 "BlockIODeviceWeight",
1045 "BlockIOReadBandwidth",
1046 "BlockIOWriteBandwidth",
1047 "CPUAccounting"))
1048 return warn_deprecated(field, eq);
1049
1050 return 0;
1051 }
1052
1053 static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
1054 if (STR_IN_SET(field, "Where",
1055 "ExtraOptions"))
1056 return bus_append_string(m, field, eq);
1057
1058 if (streq(field, "DirectoryMode"))
1059 return bus_append_parse_mode(m, field, eq);
1060
1061 if (streq(field, "TimeoutIdleSec"))
1062 return bus_append_parse_sec_rename(m, field, eq);
1063
1064 return 0;
1065 }
1066
1067 static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
1068 const char *suffix;
1069 int r;
1070
1071 if (STR_IN_SET(field, "User",
1072 "Group",
1073 "UtmpIdentifier",
1074 "UtmpMode",
1075 "PAMName",
1076 "TTYPath",
1077 "WorkingDirectory",
1078 "RootDirectory",
1079 "SyslogIdentifier",
1080 "ProtectSystem",
1081 "ProtectHome",
1082 "PrivateTmpEx",
1083 "PrivateUsersEx",
1084 "ProtectControlGroupsEx",
1085 "SELinuxContext",
1086 "RootImage",
1087 "RootVerity",
1088 "RuntimeDirectoryPreserve",
1089 "Personality",
1090 "KeyringMode",
1091 "ProtectProc",
1092 "ProcSubset",
1093 "NetworkNamespacePath",
1094 "IPCNamespacePath",
1095 "LogNamespace",
1096 "RootImagePolicy",
1097 "MountImagePolicy",
1098 "ExtensionImagePolicy",
1099 "PrivatePIDs"))
1100 return bus_append_string(m, field, eq);
1101
1102 if (STR_IN_SET(field, "IgnoreSIGPIPE",
1103 "TTYVHangup",
1104 "TTYReset",
1105 "TTYVTDisallocate",
1106 "PrivateTmp",
1107 "PrivateDevices",
1108 "PrivateNetwork",
1109 "PrivateUsers",
1110 "PrivateMounts",
1111 "PrivateIPC",
1112 "NoNewPrivileges",
1113 "SyslogLevelPrefix",
1114 "MemoryDenyWriteExecute",
1115 "RestrictRealtime",
1116 "DynamicUser",
1117 "RemoveIPC",
1118 "ProtectKernelTunables",
1119 "ProtectKernelModules",
1120 "ProtectKernelLogs",
1121 "ProtectClock",
1122 "ProtectControlGroups",
1123 "MountAPIVFS",
1124 "BindLogSockets",
1125 "CPUSchedulingResetOnFork",
1126 "LockPersonality",
1127 "ProtectHostname",
1128 "MemoryKSM",
1129 "RestrictSUIDSGID",
1130 "RootEphemeral",
1131 "SetLoginEnvironment"))
1132 return bus_append_parse_boolean(m, field, eq);
1133
1134 if (STR_IN_SET(field, "ReadWriteDirectories",
1135 "ReadOnlyDirectories",
1136 "InaccessibleDirectories",
1137 "ReadWritePaths",
1138 "ReadOnlyPaths",
1139 "InaccessiblePaths",
1140 "ExecPaths",
1141 "NoExecPaths",
1142 "ExecSearchPath",
1143 "ExtensionDirectories",
1144 "ConfigurationDirectory",
1145 "SupplementaryGroups",
1146 "SystemCallArchitectures"))
1147 return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
1148
1149 if (STR_IN_SET(field, "SyslogLevel",
1150 "LogLevelMax"))
1151 return bus_append_log_level_from_string(m, field, eq);
1152
1153 if (streq(field, "SyslogFacility"))
1154 return bus_append_log_facility_unshifted_from_string(m, field, eq);
1155
1156 if (streq(field, "SecureBits"))
1157 return bus_append_secure_bits_from_string(m, field, eq);
1158
1159 if (streq(field, "CPUSchedulingPolicy"))
1160 return bus_append_sched_policy_from_string(m, field, eq);
1161
1162 if (STR_IN_SET(field, "CPUSchedulingPriority",
1163 "OOMScoreAdjust"))
1164 return bus_append_safe_atoi(m, field, eq);
1165
1166 if (streq(field, "CoredumpFilter"))
1167 return bus_append_coredump_filter_mask_from_string(m, field, eq);
1168
1169 if (streq(field, "Nice"))
1170 return bus_append_parse_nice(m, field, eq);
1171
1172 if (streq(field, "SystemCallErrorNumber"))
1173 return bus_append_seccomp_parse_errno_or_action(m, field, eq);
1174
1175 if (streq(field, "IOSchedulingClass"))
1176 return bus_append_ioprio_class_from_string(m, field, eq);
1177
1178 if (streq(field, "IOSchedulingPriority"))
1179 return bus_append_ioprio_parse_priority(m, field, eq);
1180
1181 if (STR_IN_SET(field, "RuntimeDirectoryMode",
1182 "StateDirectoryMode",
1183 "CacheDirectoryMode",
1184 "LogsDirectoryMode",
1185 "ConfigurationDirectoryMode",
1186 "UMask"))
1187 return bus_append_parse_mode(m, field, eq);
1188
1189 if (streq(field, "TimerSlackNSec"))
1190 return bus_append_parse_nsec(m, field, eq);
1191
1192 if (streq(field, "LogRateLimitIntervalSec"))
1193 return bus_append_parse_sec_rename(m, field, eq);
1194
1195 if (STR_IN_SET(field, "LogRateLimitBurst",
1196 "TTYRows",
1197 "TTYColumns"))
1198 return bus_append_safe_atou(m, field, eq);
1199
1200 if (streq(field, "MountFlags"))
1201 return bus_append_mount_propagation_flag_from_string(m, field, eq);
1202
1203 if (STR_IN_SET(field, "Environment",
1204 "UnsetEnvironment",
1205 "PassEnvironment"))
1206 return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
1207
1208 if (streq(field, "EnvironmentFile")) {
1209 if (isempty(eq))
1210 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1211 else
1212 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1213 eq[0] == '-' ? eq + 1 : eq,
1214 eq[0] == '-');
1215 if (r < 0)
1216 return bus_log_create_error(r);
1217
1218 return 1;
1219 }
1220
1221 if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
1222 r = sd_bus_message_open_container(m, 'r', "sv");
1223 if (r < 0)
1224 return bus_log_create_error(r);
1225
1226 r = sd_bus_message_append_basic(m, 's', field);
1227 if (r < 0)
1228 return bus_log_create_error(r);
1229
1230 r = sd_bus_message_open_container(m, 'v', "a(say)");
1231 if (r < 0)
1232 return bus_log_create_error(r);
1233
1234 if (isempty(eq))
1235 r = sd_bus_message_append(m, "a(say)", 0);
1236 else {
1237 _cleanup_free_ char *word = NULL;
1238 const char *p = eq;
1239
1240 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1241 if (r == -ENOMEM)
1242 return log_oom();
1243 if (r < 0)
1244 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
1245 if (r == 0 || !p)
1246 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
1247
1248 r = sd_bus_message_open_container(m, 'a', "(say)");
1249 if (r < 0)
1250 return bus_log_create_error(r);
1251
1252 r = sd_bus_message_open_container(m, 'r', "say");
1253 if (r < 0)
1254 return bus_log_create_error(r);
1255
1256 r = sd_bus_message_append(m, "s", word);
1257 if (r < 0)
1258 return bus_log_create_error(r);
1259
1260 if (streq(field, "SetCredentialEncrypted")) {
1261 _cleanup_free_ void *decoded = NULL;
1262 size_t decoded_size;
1263
1264 r = unbase64mem(p, &decoded, &decoded_size);
1265 if (r < 0)
1266 return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
1267
1268 r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
1269 } else {
1270 _cleanup_free_ char *unescaped = NULL;
1271 ssize_t l;
1272
1273 l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
1274 if (l < 0)
1275 return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
1276
1277 r = sd_bus_message_append_array(m, 'y', unescaped, l);
1278 }
1279 if (r < 0)
1280 return bus_log_create_error(r);
1281
1282 r = sd_bus_message_close_container(m);
1283 if (r < 0)
1284 return bus_log_create_error(r);
1285
1286 r = sd_bus_message_close_container(m);
1287 }
1288 if (r < 0)
1289 return bus_log_create_error(r);
1290
1291 r = sd_bus_message_close_container(m);
1292 if (r < 0)
1293 return bus_log_create_error(r);
1294
1295 r = sd_bus_message_close_container(m);
1296 if (r < 0)
1297 return bus_log_create_error(r);
1298
1299 return 1;
1300 }
1301
1302 if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
1303 r = sd_bus_message_open_container(m, 'r', "sv");
1304 if (r < 0)
1305 return bus_log_create_error(r);
1306
1307 r = sd_bus_message_append_basic(m, 's', field);
1308 if (r < 0)
1309 return bus_log_create_error(r);
1310
1311 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1312 if (r < 0)
1313 return bus_log_create_error(r);
1314
1315 if (isempty(eq))
1316 r = sd_bus_message_append(m, "a(ss)", 0);
1317 else {
1318 _cleanup_free_ char *word = NULL;
1319 const char *p = eq;
1320
1321 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1322 if (r == -ENOMEM)
1323 return log_oom();
1324 if (r < 0)
1325 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
1326 if (r == 0)
1327 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
1328
1329 if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
1330 p = eq;
1331
1332 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1333 }
1334 if (r < 0)
1335 return bus_log_create_error(r);
1336
1337 r = sd_bus_message_close_container(m);
1338 if (r < 0)
1339 return bus_log_create_error(r);
1340
1341 r = sd_bus_message_close_container(m);
1342 if (r < 0)
1343 return bus_log_create_error(r);
1344
1345 return 1;
1346 }
1347
1348 if (streq(field, "ImportCredential")) {
1349 if (isempty(eq))
1350 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
1351 else
1352 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
1353 if (r < 0)
1354 return bus_log_create_error(r);
1355
1356 return 1;
1357 }
1358
1359 if (streq(field, "ImportCredentialEx")) {
1360 r = sd_bus_message_open_container(m, 'r', "sv");
1361 if (r < 0)
1362 return bus_log_create_error(r);
1363
1364 r = sd_bus_message_append_basic(m, 's', field);
1365 if (r < 0)
1366 return bus_log_create_error(r);
1367
1368 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1369 if (r < 0)
1370 return bus_log_create_error(r);
1371
1372 if (isempty(eq))
1373 r = sd_bus_message_append(m, "a(ss)", 0);
1374 else {
1375 _cleanup_free_ char *word = NULL;
1376 const char *p = eq;
1377
1378 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1379 if (r == -ENOMEM)
1380 return log_oom();
1381 if (r < 0)
1382 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
1383 if (r == 0)
1384 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
1385
1386 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1387 }
1388 if (r < 0)
1389 return bus_log_create_error(r);
1390
1391 r = sd_bus_message_close_container(m);
1392 if (r < 0)
1393 return bus_log_create_error(r);
1394
1395 r = sd_bus_message_close_container(m);
1396 if (r < 0)
1397 return bus_log_create_error(r);
1398
1399 return 1;
1400 }
1401
1402 if (streq(field, "LogExtraFields")) {
1403 r = sd_bus_message_open_container(m, 'r', "sv");
1404 if (r < 0)
1405 return bus_log_create_error(r);
1406
1407 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
1408 if (r < 0)
1409 return bus_log_create_error(r);
1410
1411 r = sd_bus_message_open_container(m, 'v', "aay");
1412 if (r < 0)
1413 return bus_log_create_error(r);
1414
1415 r = sd_bus_message_open_container(m, 'a', "ay");
1416 if (r < 0)
1417 return bus_log_create_error(r);
1418
1419 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
1420 if (r < 0)
1421 return bus_log_create_error(r);
1422
1423 r = sd_bus_message_close_container(m);
1424 if (r < 0)
1425 return bus_log_create_error(r);
1426
1427 r = sd_bus_message_close_container(m);
1428 if (r < 0)
1429 return bus_log_create_error(r);
1430
1431 r = sd_bus_message_close_container(m);
1432 if (r < 0)
1433 return bus_log_create_error(r);
1434
1435 return 1;
1436 }
1437
1438 if (streq(field, "LogFilterPatterns")) {
1439 r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1440 eq[0] != '~',
1441 eq[0] != '~' ? eq : eq + 1);
1442 if (r < 0)
1443 return bus_log_create_error(r);
1444
1445 return 1;
1446 }
1447
1448 if (STR_IN_SET(field, "StandardInput",
1449 "StandardOutput",
1450 "StandardError")) {
1451 const char *n, *appended;
1452
1453 if ((n = startswith(eq, "fd:"))) {
1454 appended = strjoina(field, "FileDescriptorName");
1455 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1456 } else if ((n = startswith(eq, "file:"))) {
1457 appended = strjoina(field, "File");
1458 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1459 } else if ((n = startswith(eq, "append:"))) {
1460 appended = strjoina(field, "FileToAppend");
1461 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1462 } else if ((n = startswith(eq, "truncate:"))) {
1463 appended = strjoina(field, "FileToTruncate");
1464 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1465 } else
1466 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
1467 if (r < 0)
1468 return bus_log_create_error(r);
1469
1470 return 1;
1471 }
1472
1473 if (streq(field, "StandardInputText")) {
1474 _cleanup_free_ char *unescaped = NULL;
1475 ssize_t l;
1476
1477 l = cunescape(eq, 0, &unescaped);
1478 if (l < 0)
1479 return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
1480
1481 if (!strextend(&unescaped, "\n"))
1482 return log_oom();
1483
1484 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1485 * programmatic interface anyway */
1486
1487 return bus_append_byte_array(m, field, unescaped, l + 1);
1488 }
1489
1490 if (streq(field, "StandardInputData")) {
1491 _cleanup_free_ void *decoded = NULL;
1492 size_t sz;
1493
1494 r = unbase64mem(eq, &decoded, &sz);
1495 if (r < 0)
1496 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
1497
1498 return bus_append_byte_array(m, field, decoded, sz);
1499 }
1500
1501 if ((suffix = startswith(field, "Limit"))) {
1502 int rl;
1503
1504 rl = rlimit_from_string(suffix);
1505 if (rl >= 0) {
1506 const char *sn;
1507 struct rlimit l;
1508
1509 r = rlimit_parse(rl, eq, &l);
1510 if (r < 0)
1511 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
1512
1513 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
1514 if (r < 0)
1515 return bus_log_create_error(r);
1516
1517 sn = strjoina(field, "Soft");
1518 r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
1519 if (r < 0)
1520 return bus_log_create_error(r);
1521
1522 return 1;
1523 }
1524 }
1525
1526 if (STR_IN_SET(field, "AppArmorProfile",
1527 "SmackProcessLabel")) {
1528 int ignore = 0;
1529 const char *s = eq;
1530
1531 if (eq[0] == '-') {
1532 ignore = 1;
1533 s = eq + 1;
1534 }
1535
1536 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
1537 if (r < 0)
1538 return bus_log_create_error(r);
1539
1540 return 1;
1541 }
1542
1543 if (STR_IN_SET(field, "CapabilityBoundingSet",
1544 "AmbientCapabilities")) {
1545 uint64_t sum = 0;
1546 bool invert = false;
1547 const char *p = eq;
1548
1549 if (*p == '~') {
1550 invert = true;
1551 p++;
1552 }
1553
1554 r = capability_set_from_string(p, &sum);
1555 if (r < 0)
1556 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
1557
1558 sum = invert ? ~sum : sum;
1559
1560 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
1561 if (r < 0)
1562 return bus_log_create_error(r);
1563
1564 return 1;
1565 }
1566
1567 if (streq(field, "CPUAffinity")) {
1568 _cleanup_(cpu_set_done) CPUSet cpuset = {};
1569 _cleanup_free_ uint8_t *array = NULL;
1570 size_t allocated;
1571
1572 if (eq && streq(eq, "numa")) {
1573 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1574 if (r < 0)
1575 return bus_log_create_error(r);
1576 return r;
1577 }
1578
1579 r = parse_cpu_set(eq, &cpuset);
1580 if (r < 0)
1581 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1582
1583 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1584 if (r < 0)
1585 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1586
1587 return bus_append_byte_array(m, field, array, allocated);
1588 }
1589
1590 if (streq(field, "NUMAPolicy")) {
1591 r = mpol_from_string(eq);
1592 if (r < 0)
1593 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1594
1595 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1596 if (r < 0)
1597 return bus_log_create_error(r);
1598
1599 return 1;
1600 }
1601
1602 if (streq(field, "NUMAMask")) {
1603 _cleanup_(cpu_set_done) CPUSet nodes = {};
1604 _cleanup_free_ uint8_t *array = NULL;
1605 size_t allocated;
1606
1607 if (eq && streq(eq, "all")) {
1608 r = numa_mask_add_all(&nodes);
1609 if (r < 0)
1610 return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1611 } else {
1612 r = parse_cpu_set(eq, &nodes);
1613 if (r < 0)
1614 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1615 }
1616
1617 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1618 if (r < 0)
1619 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1620
1621 return bus_append_byte_array(m, field, array, allocated);
1622 }
1623
1624 if (STR_IN_SET(field, "RestrictAddressFamilies",
1625 "RestrictFileSystems",
1626 "SystemCallFilter",
1627 "SystemCallLog",
1628 "RestrictNetworkInterfaces")) {
1629 int allow_list = 1;
1630 const char *p = eq;
1631
1632 if (*p == '~') {
1633 allow_list = 0;
1634 p++;
1635 }
1636
1637 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1638 if (r < 0)
1639 return bus_log_create_error(r);
1640
1641 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1642 if (r < 0)
1643 return bus_log_create_error(r);
1644
1645 r = sd_bus_message_open_container(m, 'v', "(bas)");
1646 if (r < 0)
1647 return bus_log_create_error(r);
1648
1649 r = sd_bus_message_open_container(m, 'r', "bas");
1650 if (r < 0)
1651 return bus_log_create_error(r);
1652
1653 r = sd_bus_message_append_basic(m, 'b', &allow_list);
1654 if (r < 0)
1655 return bus_log_create_error(r);
1656
1657 r = sd_bus_message_open_container(m, 'a', "s");
1658 if (r < 0)
1659 return bus_log_create_error(r);
1660
1661 for (;;) {
1662 _cleanup_free_ char *word = NULL;
1663
1664 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1665 if (r == 0)
1666 break;
1667 if (r == -ENOMEM)
1668 return log_oom();
1669 if (r < 0)
1670 return log_error_errno(r, "Invalid syntax: %s", eq);
1671
1672 r = sd_bus_message_append_basic(m, 's', word);
1673 if (r < 0)
1674 return bus_log_create_error(r);
1675 }
1676
1677 r = sd_bus_message_close_container(m);
1678 if (r < 0)
1679 return bus_log_create_error(r);
1680
1681 r = sd_bus_message_close_container(m);
1682 if (r < 0)
1683 return bus_log_create_error(r);
1684
1685 r = sd_bus_message_close_container(m);
1686 if (r < 0)
1687 return bus_log_create_error(r);
1688
1689 r = sd_bus_message_close_container(m);
1690 if (r < 0)
1691 return bus_log_create_error(r);
1692
1693 return 1;
1694 }
1695
1696 if (STR_IN_SET(field, "RestrictNamespaces",
1697 "DelegateNamespaces")) {
1698 bool invert = false;
1699 unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
1700 unsigned long flags;
1701
1702 r = parse_boolean(eq);
1703 if (r > 0)
1704 /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1705 * namespaces which are retained), so RestrictNamespaces=true means we retain no
1706 * access to any namespaces and vice-versa. */
1707 flags = streq(field, "RestrictNamespaces") ? 0 : all;
1708 else if (r == 0)
1709 flags = streq(field, "RestrictNamespaces") ? all : 0;
1710 else {
1711 if (eq[0] == '~') {
1712 invert = true;
1713 eq++;
1714 }
1715
1716 r = namespace_flags_from_string(eq, &flags);
1717 if (r < 0)
1718 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1719 }
1720
1721 if (invert)
1722 flags = (~flags) & all;
1723
1724 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1725 if (r < 0)
1726 return bus_log_create_error(r);
1727
1728 return 1;
1729 }
1730
1731 if (STR_IN_SET(field, "BindPaths",
1732 "BindReadOnlyPaths")) {
1733 const char *p = eq;
1734
1735 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1736 if (r < 0)
1737 return bus_log_create_error(r);
1738
1739 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1740 if (r < 0)
1741 return bus_log_create_error(r);
1742
1743 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1744 if (r < 0)
1745 return bus_log_create_error(r);
1746
1747 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1748 if (r < 0)
1749 return bus_log_create_error(r);
1750
1751 for (;;) {
1752 _cleanup_free_ char *source = NULL, *destination = NULL;
1753 char *s = NULL, *d = NULL;
1754 bool ignore_enoent = false;
1755 uint64_t flags = MS_REC;
1756
1757 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1758 if (r < 0)
1759 return log_error_errno(r, "Failed to parse argument: %m");
1760 if (r == 0)
1761 break;
1762
1763 s = source;
1764 if (s[0] == '-') {
1765 ignore_enoent = true;
1766 s++;
1767 }
1768
1769 if (p && p[-1] == ':') {
1770 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1771 if (r < 0)
1772 return log_error_errno(r, "Failed to parse argument: %m");
1773 if (r == 0)
1774 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1775 "Missing argument after ':': %s",
1776 eq);
1777
1778 d = destination;
1779
1780 if (p && p[-1] == ':') {
1781 _cleanup_free_ char *options = NULL;
1782
1783 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
1784 if (r < 0)
1785 return log_error_errno(r, "Failed to parse argument: %m");
1786
1787 if (isempty(options) || streq(options, "rbind"))
1788 flags = MS_REC;
1789 else if (streq(options, "norbind"))
1790 flags = 0;
1791 else
1792 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1793 "Unknown options: %s",
1794 eq);
1795 }
1796 } else
1797 d = s;
1798
1799 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1800 if (r < 0)
1801 return bus_log_create_error(r);
1802 }
1803
1804 r = sd_bus_message_close_container(m);
1805 if (r < 0)
1806 return bus_log_create_error(r);
1807
1808 r = sd_bus_message_close_container(m);
1809 if (r < 0)
1810 return bus_log_create_error(r);
1811
1812 r = sd_bus_message_close_container(m);
1813 if (r < 0)
1814 return bus_log_create_error(r);
1815
1816 return 1;
1817 }
1818
1819 if (streq(field, "TemporaryFileSystem")) {
1820 const char *p = eq;
1821
1822 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1823 if (r < 0)
1824 return bus_log_create_error(r);
1825
1826 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1827 if (r < 0)
1828 return bus_log_create_error(r);
1829
1830 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1831 if (r < 0)
1832 return bus_log_create_error(r);
1833
1834 r = sd_bus_message_open_container(m, 'a', "(ss)");
1835 if (r < 0)
1836 return bus_log_create_error(r);
1837
1838 for (;;) {
1839 _cleanup_free_ char *word = NULL, *path = NULL;
1840 const char *w;
1841
1842 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1843 if (r < 0)
1844 return log_error_errno(r, "Failed to parse argument: %m");
1845 if (r == 0)
1846 break;
1847
1848 w = word;
1849 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1850 if (r < 0)
1851 return log_error_errno(r, "Failed to parse argument: %m");
1852 if (r == 0)
1853 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1854 "Failed to parse argument: %s",
1855 p);
1856
1857 r = sd_bus_message_append(m, "(ss)", path, w);
1858 if (r < 0)
1859 return bus_log_create_error(r);
1860 }
1861
1862 r = sd_bus_message_close_container(m);
1863 if (r < 0)
1864 return bus_log_create_error(r);
1865
1866 r = sd_bus_message_close_container(m);
1867 if (r < 0)
1868 return bus_log_create_error(r);
1869
1870 r = sd_bus_message_close_container(m);
1871 if (r < 0)
1872 return bus_log_create_error(r);
1873
1874 return 1;
1875 }
1876
1877 if (streq(field, "RootHash")) {
1878 _cleanup_free_ void *roothash_decoded = NULL;
1879 size_t roothash_decoded_size = 0;
1880
1881 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1882 if (path_is_absolute(eq))
1883 return bus_append_string(m, "RootHashPath", eq);
1884
1885 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1886 r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
1887 if (r < 0)
1888 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1889 if (roothash_decoded_size < sizeof(sd_id128_t))
1890 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
1891
1892 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1893 }
1894
1895 if (streq(field, "RootHashSignature")) {
1896 _cleanup_free_ void *roothash_sig_decoded = NULL;
1897 char *value;
1898 size_t roothash_sig_decoded_size = 0;
1899
1900 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1901 if (path_is_absolute(eq))
1902 return bus_append_string(m, "RootHashSignaturePath", eq);
1903
1904 if (!(value = startswith(eq, "base64:")))
1905 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:'.", eq);
1906
1907 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1908 r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
1909 if (r < 0)
1910 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1911
1912 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1913 }
1914
1915 if (streq(field, "RootImageOptions")) {
1916 _cleanup_strv_free_ char **l = NULL;
1917 const char *p = eq;
1918
1919 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1920 if (r < 0)
1921 return bus_log_create_error(r);
1922
1923 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1924 if (r < 0)
1925 return bus_log_create_error(r);
1926
1927 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1928 if (r < 0)
1929 return bus_log_create_error(r);
1930
1931 r = sd_bus_message_open_container(m, 'a', "(ss)");
1932 if (r < 0)
1933 return bus_log_create_error(r);
1934
1935 r = strv_split_colon_pairs(&l, p);
1936 if (r < 0)
1937 return log_error_errno(r, "Failed to parse argument: %m");
1938
1939 STRV_FOREACH_PAIR(first, second, l) {
1940 r = sd_bus_message_append(m, "(ss)",
1941 !isempty(*second) ? *first : "root",
1942 !isempty(*second) ? *second : *first);
1943 if (r < 0)
1944 return bus_log_create_error(r);
1945 }
1946
1947 r = sd_bus_message_close_container(m);
1948 if (r < 0)
1949 return bus_log_create_error(r);
1950
1951 r = sd_bus_message_close_container(m);
1952 if (r < 0)
1953 return bus_log_create_error(r);
1954
1955 r = sd_bus_message_close_container(m);
1956 if (r < 0)
1957 return bus_log_create_error(r);
1958
1959 return 1;
1960 }
1961
1962 if (streq(field, "MountImages")) {
1963 const char *p = eq;
1964
1965 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1966 if (r < 0)
1967 return bus_log_create_error(r);
1968
1969 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1970 if (r < 0)
1971 return bus_log_create_error(r);
1972
1973 r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
1974 if (r < 0)
1975 return bus_log_create_error(r);
1976
1977 r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
1978 if (r < 0)
1979 return bus_log_create_error(r);
1980
1981 for (;;) {
1982 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
1983 const char *q = NULL, *source = NULL;
1984 bool permissive = false;
1985
1986 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1987 if (r < 0)
1988 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1989 if (r == 0)
1990 break;
1991
1992 q = tuple;
1993 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
1994 if (r < 0)
1995 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1996 if (r == 0)
1997 continue;
1998
1999 source = first;
2000 if (source[0] == '-') {
2001 permissive = true;
2002 source++;
2003 }
2004
2005 if (isempty(second))
2006 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2007 "Missing argument after ':': %s",
2008 eq);
2009
2010 r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
2011 if (r < 0)
2012 return bus_log_create_error(r);
2013
2014 r = sd_bus_message_append(m, "ssb", source, second, permissive);
2015 if (r < 0)
2016 return bus_log_create_error(r);
2017
2018 r = sd_bus_message_open_container(m, 'a', "(ss)");
2019 if (r < 0)
2020 return bus_log_create_error(r);
2021
2022 for (;;) {
2023 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2024
2025 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
2026 if (r < 0)
2027 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
2028 if (r == 0)
2029 break;
2030 /* Single set of options, applying to the root partition/single filesystem */
2031 if (r == 1) {
2032 r = sd_bus_message_append(m, "(ss)", "root", partition);
2033 if (r < 0)
2034 return bus_log_create_error(r);
2035
2036 break;
2037 }
2038
2039 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2040 if (r < 0)
2041 return bus_log_create_error(r);
2042 }
2043
2044 r = sd_bus_message_close_container(m);
2045 if (r < 0)
2046 return bus_log_create_error(r);
2047
2048 r = sd_bus_message_close_container(m);
2049 if (r < 0)
2050 return bus_log_create_error(r);
2051 }
2052
2053 r = sd_bus_message_close_container(m);
2054 if (r < 0)
2055 return bus_log_create_error(r);
2056
2057 r = sd_bus_message_close_container(m);
2058 if (r < 0)
2059 return bus_log_create_error(r);
2060
2061 r = sd_bus_message_close_container(m);
2062 if (r < 0)
2063 return bus_log_create_error(r);
2064
2065 return 1;
2066 }
2067
2068 if (streq(field, "ExtensionImages")) {
2069 const char *p = eq;
2070
2071 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2072 if (r < 0)
2073 return bus_log_create_error(r);
2074
2075 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2076 if (r < 0)
2077 return bus_log_create_error(r);
2078
2079 r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
2080 if (r < 0)
2081 return bus_log_create_error(r);
2082
2083 r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
2084 if (r < 0)
2085 return bus_log_create_error(r);
2086
2087 for (;;) {
2088 _cleanup_free_ char *source = NULL, *tuple = NULL;
2089 const char *q = NULL, *s = NULL;
2090 bool permissive = false;
2091
2092 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
2093 if (r < 0)
2094 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
2095 if (r == 0)
2096 break;
2097
2098 q = tuple;
2099 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
2100 if (r < 0)
2101 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
2102 if (r == 0)
2103 continue;
2104
2105 s = source;
2106 if (s[0] == '-') {
2107 permissive = true;
2108 s++;
2109 }
2110
2111 r = sd_bus_message_open_container(m, 'r', "sba(ss)");
2112 if (r < 0)
2113 return bus_log_create_error(r);
2114
2115 r = sd_bus_message_append(m, "sb", s, permissive);
2116 if (r < 0)
2117 return bus_log_create_error(r);
2118
2119 r = sd_bus_message_open_container(m, 'a', "(ss)");
2120 if (r < 0)
2121 return bus_log_create_error(r);
2122
2123 for (;;) {
2124 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2125
2126 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
2127 if (r < 0)
2128 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
2129 if (r == 0)
2130 break;
2131 /* Single set of options, applying to the root partition/single filesystem */
2132 if (r == 1) {
2133 r = sd_bus_message_append(m, "(ss)", "root", partition);
2134 if (r < 0)
2135 return bus_log_create_error(r);
2136
2137 break;
2138 }
2139
2140 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2141 if (r < 0)
2142 return bus_log_create_error(r);
2143 }
2144
2145 r = sd_bus_message_close_container(m);
2146 if (r < 0)
2147 return bus_log_create_error(r);
2148
2149 r = sd_bus_message_close_container(m);
2150 if (r < 0)
2151 return bus_log_create_error(r);
2152 }
2153
2154 r = sd_bus_message_close_container(m);
2155 if (r < 0)
2156 return bus_log_create_error(r);
2157
2158 r = sd_bus_message_close_container(m);
2159 if (r < 0)
2160 return bus_log_create_error(r);
2161
2162 r = sd_bus_message_close_container(m);
2163 if (r < 0)
2164 return bus_log_create_error(r);
2165
2166 return 1;
2167 }
2168
2169 if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
2170 _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
2171 const char *p = eq;
2172
2173 /* Adding new directories is supported from both *DirectorySymlink methods and the
2174 * older ones, so first parse the input, and if we are given a new-style src:dst
2175 * tuple use the new method, else use the old one. */
2176
2177 for (;;) {
2178 _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
2179
2180 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
2181 if (r < 0)
2182 return log_error_errno(r, "Failed to parse argument: %m");
2183 if (r == 0)
2184 break;
2185
2186 const char *t = tuple;
2187 r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
2188 if (r <= 0)
2189 return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
2190
2191 path_simplify(source);
2192
2193 if (isempty(dest) && isempty(flags)) {
2194 r = strv_consume(&sources, TAKE_PTR(source));
2195 if (r < 0)
2196 return bus_log_create_error(r);
2197 } else if (isempty(flags)) {
2198 path_simplify(dest);
2199 r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
2200 if (r < 0)
2201 return log_oom();
2202 } else {
2203 ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
2204 if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
2205 return log_error_errno(r, "Failed to parse flags: %s", flags);
2206
2207 if (!isempty(dest)) {
2208 path_simplify(dest);
2209 r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
2210 } else
2211 r = strv_consume(&sources_ro, TAKE_PTR(source));
2212 if (r < 0)
2213 return log_oom();
2214 }
2215 }
2216
2217 if (!strv_isempty(sources)) {
2218 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2219 if (r < 0)
2220 return bus_log_create_error(r);
2221
2222 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2223 if (r < 0)
2224 return bus_log_create_error(r);
2225
2226 r = sd_bus_message_open_container(m, 'v', "as");
2227 if (r < 0)
2228 return bus_log_create_error(r);
2229
2230 r = sd_bus_message_append_strv(m, sources);
2231 if (r < 0)
2232 return bus_log_create_error(r);
2233
2234 r = sd_bus_message_close_container(m);
2235 if (r < 0)
2236 return bus_log_create_error(r);
2237
2238 r = sd_bus_message_close_container(m);
2239 if (r < 0)
2240 return bus_log_create_error(r);
2241 }
2242
2243 /* For State and Runtime directories we support an optional destination parameter, which
2244 * will be used to create a symlink to the source. But it is new so we cannot change the
2245 * old DBUS signatures, so append a new message type. */
2246 if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) {
2247 const char *symlink_field;
2248
2249 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2250 if (r < 0)
2251 return bus_log_create_error(r);
2252
2253 if (streq(field, "StateDirectory"))
2254 symlink_field = "StateDirectorySymlink";
2255 else if (streq(field, "RuntimeDirectory"))
2256 symlink_field = "RuntimeDirectorySymlink";
2257 else if (streq(field, "CacheDirectory"))
2258 symlink_field = "CacheDirectorySymlink";
2259 else if (streq(field, "LogsDirectory"))
2260 symlink_field = "LogsDirectorySymlink";
2261 else
2262 assert_not_reached();
2263
2264 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
2265 if (r < 0)
2266 return bus_log_create_error(r);
2267
2268 r = sd_bus_message_open_container(m, 'v', "a(sst)");
2269 if (r < 0)
2270 return bus_log_create_error(r);
2271
2272 r = sd_bus_message_open_container(m, 'a', "(sst)");
2273 if (r < 0)
2274 return bus_log_create_error(r);
2275
2276 STRV_FOREACH_PAIR(source, destination, symlinks) {
2277 r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
2278 if (r < 0)
2279 return bus_log_create_error(r);
2280 }
2281
2282 STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
2283 r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
2284 if (r < 0)
2285 return bus_log_create_error(r);
2286 }
2287
2288 STRV_FOREACH(source, sources_ro) {
2289 r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
2290 if (r < 0)
2291 return bus_log_create_error(r);
2292 }
2293
2294 r = sd_bus_message_close_container(m);
2295 if (r < 0)
2296 return bus_log_create_error(r);
2297
2298 r = sd_bus_message_close_container(m);
2299 if (r < 0)
2300 return bus_log_create_error(r);
2301
2302 r = sd_bus_message_close_container(m);
2303 if (r < 0)
2304 return bus_log_create_error(r);
2305 }
2306
2307 return 1;
2308 }
2309
2310 if (streq(field, "ProtectHostnameEx")) {
2311 const char *colon = strchr(eq, ':');
2312 if (colon) {
2313 if (isempty(colon + 1))
2314 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
2315
2316 _cleanup_free_ char *p = strndup(eq, colon - eq);
2317 if (!p)
2318 return -ENOMEM;
2319
2320 r = sd_bus_message_append(m, "(sv)", field, "(ss)", p, colon + 1);
2321 } else
2322 r = sd_bus_message_append(m, "(sv)", field, "(ss)", eq, NULL);
2323 if (r < 0)
2324 return bus_log_create_error(r);
2325
2326 return 1;
2327 }
2328 return 0;
2329 }
2330
2331 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
2332 if (streq(field, "KillMode"))
2333 return bus_append_string(m, field, eq);
2334
2335 if (STR_IN_SET(field, "SendSIGHUP",
2336 "SendSIGKILL"))
2337 return bus_append_parse_boolean(m, field, eq);
2338
2339 if (STR_IN_SET(field, "KillSignal",
2340 "RestartKillSignal",
2341 "FinalKillSignal",
2342 "WatchdogSignal",
2343 "ReloadSignal"))
2344 return bus_append_signal_from_string(m, field, eq);
2345
2346 return 0;
2347 }
2348
2349 static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
2350
2351 if (STR_IN_SET(field, "What",
2352 "Where",
2353 "Options",
2354 "Type"))
2355 return bus_append_string(m, field, eq);
2356
2357 if (streq(field, "TimeoutSec"))
2358 return bus_append_parse_sec_rename(m, field, eq);
2359
2360 if (streq(field, "DirectoryMode"))
2361 return bus_append_parse_mode(m, field, eq);
2362
2363 if (STR_IN_SET(field, "SloppyOptions",
2364 "LazyUnmount",
2365 "ForceUnmount",
2366 "ReadwriteOnly"))
2367 return bus_append_parse_boolean(m, field, eq);
2368
2369 return 0;
2370 }
2371
2372 static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
2373 int r;
2374
2375 if (streq(field, "MakeDirectory"))
2376 return bus_append_parse_boolean(m, field, eq);
2377
2378 if (streq(field, "DirectoryMode"))
2379 return bus_append_parse_mode(m, field, eq);
2380
2381 if (STR_IN_SET(field, "PathExists",
2382 "PathExistsGlob",
2383 "PathChanged",
2384 "PathModified",
2385 "DirectoryNotEmpty")) {
2386 if (isempty(eq))
2387 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
2388 else
2389 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
2390 if (r < 0)
2391 return bus_log_create_error(r);
2392
2393 return 1;
2394 }
2395
2396 if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
2397 return bus_append_safe_atou(m, field, eq);
2398
2399 if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
2400 return bus_append_parse_sec_rename(m, field, eq);
2401
2402 return 0;
2403 }
2404
2405 static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
2406 if (streq(field, "RuntimeMaxSec"))
2407 return bus_append_parse_sec_rename(m, field, eq);
2408
2409 if (streq(field, "RuntimeRandomizedExtraSec"))
2410 return bus_append_parse_sec_rename(m, field, eq);
2411
2412 if (streq(field, "TimeoutStopSec"))
2413 return bus_append_parse_sec_rename(m, field, eq);
2414
2415 /* Scope units don't have execution context but we still want to allow setting these two,
2416 * so let's handle them separately. */
2417 if (STR_IN_SET(field, "User", "Group"))
2418 return bus_append_string(m, field, eq);
2419
2420 if (streq(field, "OOMPolicy"))
2421 return bus_append_string(m, field, eq);
2422
2423 return 0;
2424 }
2425
2426 static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
2427 int r;
2428
2429 if (STR_IN_SET(field, "PIDFile",
2430 "Type",
2431 "ExitType",
2432 "Restart",
2433 "RestartMode",
2434 "BusName",
2435 "NotifyAccess",
2436 "USBFunctionDescriptors",
2437 "USBFunctionStrings",
2438 "OOMPolicy",
2439 "TimeoutStartFailureMode",
2440 "TimeoutStopFailureMode",
2441 "FileDescriptorStorePreserve"))
2442 return bus_append_string(m, field, eq);
2443
2444 if (STR_IN_SET(field, "PermissionsStartOnly",
2445 "RootDirectoryStartOnly",
2446 "RemainAfterExit",
2447 "GuessMainPID"))
2448 return bus_append_parse_boolean(m, field, eq);
2449
2450 if (STR_IN_SET(field, "RestartSec",
2451 "RestartMaxDelaySec",
2452 "TimeoutStartSec",
2453 "TimeoutStopSec",
2454 "TimeoutAbortSec",
2455 "RuntimeMaxSec",
2456 "RuntimeRandomizedExtraSec",
2457 "WatchdogSec"))
2458 return bus_append_parse_sec_rename(m, field, eq);
2459
2460 if (streq(field, "TimeoutSec")) {
2461 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2462 if (r < 0)
2463 return r;
2464
2465 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2466 }
2467
2468 if (STR_IN_SET(field, "FileDescriptorStoreMax",
2469 "RestartSteps"))
2470 return bus_append_safe_atou(m, field, eq);
2471
2472 if (STR_IN_SET(field, "ExecCondition",
2473 "ExecStartPre",
2474 "ExecStart",
2475 "ExecStartPost",
2476 "ExecConditionEx",
2477 "ExecStartPreEx",
2478 "ExecStartEx",
2479 "ExecStartPostEx",
2480 "ExecReload",
2481 "ExecStop",
2482 "ExecStopPost",
2483 "ExecReloadEx",
2484 "ExecStopEx",
2485 "ExecStopPostEx"))
2486 return bus_append_exec_command(m, field, eq);
2487
2488 if (STR_IN_SET(field, "RestartPreventExitStatus",
2489 "RestartForceExitStatus",
2490 "SuccessExitStatus")) {
2491 _cleanup_free_ int *status = NULL, *signal = NULL;
2492 size_t n_status = 0, n_signal = 0;
2493 const char *p;
2494
2495 for (p = eq;;) {
2496 _cleanup_free_ char *word = NULL;
2497
2498 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2499 if (r == 0)
2500 break;
2501 if (r == -ENOMEM)
2502 return log_oom();
2503 if (r < 0)
2504 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2505
2506 /* We need to call exit_status_from_string() first, because we want
2507 * to parse numbers as exit statuses, not signals. */
2508
2509 r = exit_status_from_string(word);
2510 if (r >= 0) {
2511 assert(r >= 0 && r < 256);
2512
2513 if (!GREEDY_REALLOC(status, n_status + 1))
2514 return log_oom();
2515
2516 status[n_status++] = r;
2517
2518 } else if ((r = signal_from_string(word)) >= 0) {
2519 if (!GREEDY_REALLOC(signal, n_signal + 1))
2520 return log_oom();
2521
2522 signal[n_signal++] = r;
2523
2524 } else
2525 /* original r from exit_status_to_string() */
2526 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2527 word, field);
2528 }
2529
2530 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2531 if (r < 0)
2532 return bus_log_create_error(r);
2533
2534 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2535 if (r < 0)
2536 return bus_log_create_error(r);
2537
2538 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2539 if (r < 0)
2540 return bus_log_create_error(r);
2541
2542 r = sd_bus_message_open_container(m, 'r', "aiai");
2543 if (r < 0)
2544 return bus_log_create_error(r);
2545
2546 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
2547 if (r < 0)
2548 return bus_log_create_error(r);
2549
2550 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
2551 if (r < 0)
2552 return bus_log_create_error(r);
2553
2554 r = sd_bus_message_close_container(m);
2555 if (r < 0)
2556 return bus_log_create_error(r);
2557
2558 r = sd_bus_message_close_container(m);
2559 if (r < 0)
2560 return bus_log_create_error(r);
2561
2562 r = sd_bus_message_close_container(m);
2563 if (r < 0)
2564 return bus_log_create_error(r);
2565
2566 return 1;
2567 }
2568
2569 if (streq(field, "OpenFile"))
2570 return bus_append_open_file(m, field, eq);
2571
2572 return 0;
2573 }
2574
2575 static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2576 int r;
2577
2578 if (STR_IN_SET(field, "Accept",
2579 "FlushPending",
2580 "Writable",
2581 "KeepAlive",
2582 "NoDelay",
2583 "FreeBind",
2584 "Transparent",
2585 "Broadcast",
2586 "PassCredentials",
2587 "PassPIDFD",
2588 "PassSecurity",
2589 "PassPacketInfo",
2590 "AcceptFileDescriptors",
2591 "ReusePort",
2592 "RemoveOnStop",
2593 "PassFileDescriptorsToExec",
2594 "SELinuxContextFromNet"))
2595 return bus_append_parse_boolean(m, field, eq);
2596
2597 if (STR_IN_SET(field, "Priority",
2598 "IPTTL",
2599 "Mark"))
2600 return bus_append_safe_atoi(m, field, eq);
2601
2602 if (streq(field, "IPTOS"))
2603 return bus_append_ip_tos_from_string(m, field, eq);
2604
2605 if (STR_IN_SET(field, "Backlog",
2606 "MaxConnections",
2607 "MaxConnectionsPerSource",
2608 "KeepAliveProbes",
2609 "TriggerLimitBurst",
2610 "PollLimitBurst"))
2611 return bus_append_safe_atou(m, field, eq);
2612
2613 if (STR_IN_SET(field, "SocketMode",
2614 "DirectoryMode"))
2615 return bus_append_parse_mode(m, field, eq);
2616
2617 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2618 "MessageQueueMessageSize"))
2619 return bus_append_safe_atoi64(m, field, eq);
2620
2621 if (STR_IN_SET(field, "TimeoutSec",
2622 "KeepAliveTimeSec",
2623 "KeepAliveIntervalSec",
2624 "DeferAcceptSec",
2625 "TriggerLimitIntervalSec",
2626 "PollLimitIntervalSec"))
2627 return bus_append_parse_sec_rename(m, field, eq);
2628
2629 if (STR_IN_SET(field, "ReceiveBuffer",
2630 "SendBuffer",
2631 "PipeSize"))
2632 return bus_append_parse_size(m, field, eq, 1024);
2633
2634 if (STR_IN_SET(field, "ExecStartPre",
2635 "ExecStartPost",
2636 "ExecReload",
2637 "ExecStopPost"))
2638 return bus_append_exec_command(m, field, eq);
2639
2640 if (STR_IN_SET(field, "SmackLabel",
2641 "SmackLabelIPIn",
2642 "SmackLabelIPOut",
2643 "TCPCongestion",
2644 "BindToDevice",
2645 "BindIPv6Only",
2646 "FileDescriptorName",
2647 "SocketUser",
2648 "SocketGroup",
2649 "Timestamping"))
2650 return bus_append_string(m, field, eq);
2651
2652 if (streq(field, "Symlinks"))
2653 return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
2654
2655 if (streq(field, "SocketProtocol"))
2656 return bus_append_parse_ip_protocol(m, field, eq);
2657
2658 if (STR_IN_SET(field, "ListenStream",
2659 "ListenDatagram",
2660 "ListenSequentialPacket",
2661 "ListenNetlink",
2662 "ListenSpecial",
2663 "ListenMessageQueue",
2664 "ListenFIFO",
2665 "ListenUSBFunction")) {
2666 if (isempty(eq))
2667 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2668 else
2669 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
2670 if (r < 0)
2671 return bus_log_create_error(r);
2672
2673 return 1;
2674 }
2675
2676 return 0;
2677 }
2678 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
2679 int r;
2680
2681 if (STR_IN_SET(field, "WakeSystem",
2682 "RemainAfterElapse",
2683 "Persistent",
2684 "OnTimezoneChange",
2685 "OnClockChange",
2686 "FixedRandomDelay",
2687 "DeferReactivation"))
2688 return bus_append_parse_boolean(m, field, eq);
2689
2690 if (STR_IN_SET(field, "AccuracySec",
2691 "RandomizedDelaySec",
2692 "RandomizedOffsetSec"))
2693 return bus_append_parse_sec_rename(m, field, eq);
2694
2695 if (STR_IN_SET(field, "OnActiveSec",
2696 "OnBootSec",
2697 "OnStartupSec",
2698 "OnUnitActiveSec",
2699 "OnUnitInactiveSec")) {
2700 if (isempty(eq))
2701 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2702 else {
2703 usec_t t;
2704 r = parse_sec(eq, &t);
2705 if (r < 0)
2706 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
2707
2708 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2709 }
2710 if (r < 0)
2711 return bus_log_create_error(r);
2712
2713 return 1;
2714 }
2715
2716 if (streq(field, "OnCalendar")) {
2717 if (isempty(eq))
2718 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2719 else
2720 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2721 if (r < 0)
2722 return bus_log_create_error(r);
2723
2724 return 1;
2725 }
2726
2727 return 0;
2728 }
2729
2730 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
2731 ConditionType t = _CONDITION_TYPE_INVALID;
2732 bool is_condition = false;
2733 int r;
2734
2735 if (STR_IN_SET(field, "Description",
2736 "SourcePath",
2737 "OnFailureJobMode",
2738 "JobTimeoutAction",
2739 "JobTimeoutRebootArgument",
2740 "StartLimitAction",
2741 "FailureAction",
2742 "SuccessAction",
2743 "RebootArgument",
2744 "CollectMode"))
2745 return bus_append_string(m, field, eq);
2746
2747 if (STR_IN_SET(field, "StopWhenUnneeded",
2748 "RefuseManualStart",
2749 "RefuseManualStop",
2750 "AllowIsolate",
2751 "IgnoreOnIsolate",
2752 "SurviveFinalKillSignal",
2753 "DefaultDependencies"))
2754 return bus_append_parse_boolean(m, field, eq);
2755
2756 if (STR_IN_SET(field, "JobTimeoutSec",
2757 "JobRunningTimeoutSec",
2758 "StartLimitIntervalSec"))
2759 return bus_append_parse_sec_rename(m, field, eq);
2760
2761 if (streq(field, "StartLimitBurst"))
2762 return bus_append_safe_atou(m, field, eq);
2763
2764 if (STR_IN_SET(field, "SuccessActionExitStatus",
2765 "FailureActionExitStatus")) {
2766 if (isempty(eq))
2767 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2768 else {
2769 uint8_t u;
2770
2771 r = safe_atou8(eq, &u);
2772 if (r < 0)
2773 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2774
2775 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2776 }
2777 if (r < 0)
2778 return bus_log_create_error(r);
2779
2780 return 1;
2781 }
2782
2783 if (unit_dependency_from_string(field) >= 0 ||
2784 STR_IN_SET(field, "Documentation",
2785 "RequiresMountsFor",
2786 "WantsMountsFor",
2787 "Markers"))
2788 return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
2789
2790 t = condition_type_from_string(field);
2791 if (t >= 0)
2792 is_condition = true;
2793 else
2794 t = assert_type_from_string(field);
2795 if (t >= 0) {
2796 if (isempty(eq))
2797 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2798 else {
2799 const char *p = eq;
2800 int trigger, negate;
2801
2802 trigger = *p == '|';
2803 if (trigger)
2804 p++;
2805
2806 negate = *p == '!';
2807 if (negate)
2808 p++;
2809
2810 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2811 field, trigger, negate, p);
2812 }
2813 if (r < 0)
2814 return bus_log_create_error(r);
2815
2816 return 1;
2817 }
2818
2819 return 0;
2820 }
2821
2822 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2823 const char *eq, *field;
2824 int r;
2825
2826 assert(m);
2827 assert(assignment);
2828
2829 eq = strchr(assignment, '=');
2830 if (!eq)
2831 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2832 "Not an assignment: %s", assignment);
2833
2834 field = strndupa_safe(assignment, eq - assignment);
2835 eq++;
2836
2837 switch (t) {
2838 case UNIT_SERVICE:
2839 r = bus_append_cgroup_property(m, field, eq);
2840 if (r != 0)
2841 return r;
2842
2843 r = bus_append_execute_property(m, field, eq);
2844 if (r != 0)
2845 return r;
2846
2847 r = bus_append_kill_property(m, field, eq);
2848 if (r != 0)
2849 return r;
2850
2851 r = bus_append_service_property(m, field, eq);
2852 if (r != 0)
2853 return r;
2854 break;
2855
2856 case UNIT_SOCKET:
2857 r = bus_append_cgroup_property(m, field, eq);
2858 if (r != 0)
2859 return r;
2860
2861 r = bus_append_execute_property(m, field, eq);
2862 if (r != 0)
2863 return r;
2864
2865 r = bus_append_kill_property(m, field, eq);
2866 if (r != 0)
2867 return r;
2868
2869 r = bus_append_socket_property(m, field, eq);
2870 if (r != 0)
2871 return r;
2872 break;
2873
2874 case UNIT_TIMER:
2875 r = bus_append_timer_property(m, field, eq);
2876 if (r != 0)
2877 return r;
2878 break;
2879
2880 case UNIT_PATH:
2881 r = bus_append_path_property(m, field, eq);
2882 if (r != 0)
2883 return r;
2884 break;
2885
2886 case UNIT_SLICE:
2887 r = bus_append_cgroup_property(m, field, eq);
2888 if (r != 0)
2889 return r;
2890 break;
2891
2892 case UNIT_SCOPE:
2893 r = bus_append_cgroup_property(m, field, eq);
2894 if (r != 0)
2895 return r;
2896
2897 r = bus_append_kill_property(m, field, eq);
2898 if (r != 0)
2899 return r;
2900
2901 r = bus_append_scope_property(m, field, eq);
2902 if (r != 0)
2903 return r;
2904 break;
2905
2906 case UNIT_MOUNT:
2907 r = bus_append_cgroup_property(m, field, eq);
2908 if (r != 0)
2909 return r;
2910
2911 r = bus_append_execute_property(m, field, eq);
2912 if (r != 0)
2913 return r;
2914
2915 r = bus_append_kill_property(m, field, eq);
2916 if (r != 0)
2917 return r;
2918
2919 r = bus_append_mount_property(m, field, eq);
2920 if (r != 0)
2921 return r;
2922
2923 break;
2924
2925 case UNIT_AUTOMOUNT:
2926 r = bus_append_automount_property(m, field, eq);
2927 if (r != 0)
2928 return r;
2929
2930 break;
2931
2932 case UNIT_TARGET:
2933 case UNIT_DEVICE:
2934 case UNIT_SWAP:
2935 break;
2936
2937 default:
2938 assert_not_reached();
2939 }
2940
2941 r = bus_append_unit_property(m, field, eq);
2942 if (r != 0)
2943 return r;
2944
2945 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2946 "Unknown assignment: %s", assignment);
2947 }
2948
2949 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char * const *l) {
2950 int r;
2951
2952 assert(m);
2953
2954 STRV_FOREACH(i, l) {
2955 r = bus_append_unit_property_assignment(m, t, *i);
2956 if (r < 0)
2957 return r;
2958 }
2959
2960 return 0;
2961 }
2962
2963 int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
2964 assert(m);
2965
2966 if (!pidref_is_set(pidref))
2967 return -ESRCH;
2968
2969 if (pidref->fd >= 0 && allow_pidfd)
2970 return sd_bus_message_append(
2971 m, "(sv)",
2972 "PIDFDs", "ah", 1, pidref->fd);
2973
2974 return sd_bus_message_append(
2975 m, "(sv)",
2976 "PIDs", "au", 1, pidref->pid);
2977 }
2978
2979 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
2980 const char *type, *path, *source;
2981 InstallChange *changes = NULL;
2982 size_t n_changes = 0;
2983 int r;
2984
2985 CLEANUP_ARRAY(changes, n_changes, install_changes_free);
2986
2987 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2988 if (r < 0)
2989 return bus_log_parse_error(r);
2990
2991 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2992 InstallChangeType t;
2993
2994 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2995 * negative. */
2996 t = install_change_type_from_string(type);
2997 if (t < 0) {
2998 log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2999 type, path);
3000 continue;
3001 }
3002
3003 r = install_changes_add(&changes, &n_changes, t, path, source);
3004 if (r < 0)
3005 return r;
3006 }
3007 if (r < 0)
3008 return bus_log_parse_error(r);
3009
3010 r = sd_bus_message_exit_container(m);
3011 if (r < 0)
3012 return bus_log_parse_error(r);
3013
3014 install_changes_dump(0, NULL, changes, n_changes, quiet);
3015
3016 return 0;
3017 }
3018
3019 int unit_load_state(sd_bus *bus, const char *name, char **ret) {
3020 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3021 _cleanup_free_ char *path = NULL;
3022 int r;
3023
3024 path = unit_dbus_path_from_name(name);
3025 if (!path)
3026 return log_oom();
3027
3028 /* This function warns on its own, because otherwise it'd be awkward to pass
3029 * the dbus error message around. */
3030
3031 r = sd_bus_get_property_string(
3032 bus,
3033 "org.freedesktop.systemd1",
3034 path,
3035 "org.freedesktop.systemd1.Unit",
3036 "LoadState",
3037 &error,
3038 ret);
3039 if (r < 0)
3040 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
3041
3042 return 0;
3043 }
3044
3045 int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
3046 int r;
3047
3048 /* First, order by machine */
3049 r = strcasecmp_ptr(a->machine, b->machine);
3050 if (r != 0)
3051 return r;
3052
3053 /* Second, order by unit type */
3054 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
3055 if (r != 0)
3056 return r;
3057
3058 /* Third, order by name */
3059 return strcasecmp(a->id, b->id);
3060 }
3061
3062 int bus_service_manager_reload(sd_bus *bus) {
3063 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3064 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
3065 int r;
3066
3067 assert(bus);
3068
3069 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
3070 if (r < 0)
3071 return bus_log_create_error(r);
3072
3073 /* Reloading the daemon may take long, hence set a longer timeout here */
3074 r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
3075 if (r < 0)
3076 return log_error_errno(r, "Failed to reload service manager: %s", bus_error_message(&error, r));
3077
3078 return 0;
3079 }
3080
3081 typedef struct UnitFreezer {
3082 char *name;
3083 sd_bus *bus;
3084 } UnitFreezer;
3085
3086 /* Wait for 60 seconds at maximum for freezer operation */
3087 #define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3088
3089 UnitFreezer* unit_freezer_free(UnitFreezer *f) {
3090 if (!f)
3091 return NULL;
3092
3093 free(f->name);
3094 sd_bus_flush_close_unref(f->bus);
3095
3096 return mfree(f);
3097 }
3098
3099 int unit_freezer_new(const char *name, UnitFreezer **ret) {
3100 _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
3101 int r;
3102
3103 assert(name);
3104 assert(ret);
3105
3106 f = new(UnitFreezer, 1);
3107 if (!f)
3108 return log_oom();
3109
3110 *f = (UnitFreezer) {
3111 .name = strdup(name),
3112 };
3113 if (!f->name)
3114 return log_oom();
3115
3116 r = bus_connect_system_systemd(&f->bus);
3117 if (r < 0)
3118 return log_error_errno(r, "Failed to open connection to systemd: %m");
3119
3120 (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
3121
3122 *ret = TAKE_PTR(f);
3123 return 0;
3124 }
3125
3126 static int unit_freezer_action(UnitFreezer *f, bool freeze) {
3127 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3128 int r;
3129
3130 assert(f);
3131 assert(f->name);
3132 assert(f->bus);
3133
3134 r = bus_call_method(f->bus, bus_systemd_mgr,
3135 freeze ? "FreezeUnit" : "ThawUnit",
3136 &error,
3137 /* ret_reply = */ NULL,
3138 "s",
3139 f->name);
3140 if (r < 0) {
3141 if (sd_bus_error_has_names(&error,
3142 BUS_ERROR_NO_SUCH_UNIT,
3143 BUS_ERROR_UNIT_INACTIVE,
3144 SD_BUS_ERROR_NOT_SUPPORTED)) {
3145
3146 log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
3147 return 0;
3148 }
3149
3150 return log_error_errno(r, "Failed to %s unit '%s': %s",
3151 freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3152 }
3153
3154 log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
3155 return 1;
3156 }
3157
3158 int unit_freezer_freeze(UnitFreezer *f) {
3159 return unit_freezer_action(f, true);
3160 }
3161
3162 int unit_freezer_thaw(UnitFreezer *f) {
3163 return unit_freezer_action(f, false);
3164 }
3165
3166 ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
3167 if (isempty(s))
3168 return 0;
3169
3170 if (streq(s, "ro"))
3171 return EXEC_DIRECTORY_READ_ONLY;
3172
3173 return _EXEC_DIRECTORY_FLAGS_INVALID;
3174 }