]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
Merge pull request #20186 from keszybz/coverity-fixes
[thirdparty/systemd.git] / src / shared / bus-unit-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "af-list.h"
4 #include "alloc-util.h"
5 #include "bus-error.h"
6 #include "bus-unit-util.h"
7 #include "bus-util.h"
8 #include "cap-list.h"
9 #include "cgroup-setup.h"
10 #include "cgroup-util.h"
11 #include "condition.h"
12 #include "coredump-util.h"
13 #include "cpu-set-util.h"
14 #include "dissect-image.h"
15 #include "escape.h"
16 #include "exec-util.h"
17 #include "exit-status.h"
18 #include "fileio.h"
19 #include "hexdecoct.h"
20 #include "hostname-util.h"
21 #include "in-addr-util.h"
22 #include "ip-protocol-list.h"
23 #include "libmount-util.h"
24 #include "locale-util.h"
25 #include "log.h"
26 #include "missing_fs.h"
27 #include "mountpoint-util.h"
28 #include "nsflags.h"
29 #include "numa-util.h"
30 #include "parse-socket-bind-item.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "percent-util.h"
34 #include "process-util.h"
35 #include "rlimit-util.h"
36 #if HAVE_SECCOMP
37 #include "seccomp-util.h"
38 #endif
39 #include "securebits-util.h"
40 #include "signal-util.h"
41 #include "socket-util.h"
42 #include "sort-util.h"
43 #include "stdio-util.h"
44 #include "string-util.h"
45 #include "syslog-util.h"
46 #include "terminal-util.h"
47 #include "unit-def.h"
48 #include "user-util.h"
49 #include "utf8.h"
50
51 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
52 assert(message);
53 assert(u);
54
55 u->machine = NULL;
56
57 return sd_bus_message_read(
58 message,
59 "(ssssssouso)",
60 &u->id,
61 &u->description,
62 &u->load_state,
63 &u->active_state,
64 &u->sub_state,
65 &u->following,
66 &u->unit_path,
67 &u->job_id,
68 &u->job_type,
69 &u->job_path);
70 }
71
72 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
73 static int bus_append_##parse_func( \
74 sd_bus_message *m, \
75 const char *field, \
76 const char *eq) { \
77 type val; \
78 int r; \
79 \
80 r = parse_func(eq, &val); \
81 if (r < 0) \
82 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
83 \
84 r = sd_bus_message_append(m, "(sv)", field, \
85 bus_type, (cast_type) val); \
86 if (r < 0) \
87 return bus_log_create_error(r); \
88 \
89 return 1; \
90 }
91
92 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
93 static int bus_append_##parse_func( \
94 sd_bus_message *m, \
95 const char *field, \
96 const char *eq) { \
97 int r; \
98 \
99 r = parse_func(eq); \
100 if (r < 0) \
101 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
102 \
103 r = sd_bus_message_append(m, "(sv)", field, \
104 bus_type, (int32_t) r); \
105 if (r < 0) \
106 return bus_log_create_error(r); \
107 \
108 return 1; \
109 }
110
111 DEFINE_BUS_APPEND_PARSE("b", parse_boolean);
112 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
113 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
114 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
115 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
116 #if !HAVE_SECCOMP
117 static inline int seccomp_parse_errno_or_action(const char *eq) { return -EINVAL; }
118 #endif
119 DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action);
120 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
121 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
122 DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
123 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
124 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
125 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
126 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
127 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
128 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse);
129 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse);
130 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
131 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
133 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
134 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
135 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
136 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string);
137
138 static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
139 int r;
140
141 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
142 if (r < 0)
143 return bus_log_create_error(r);
144
145 return 1;
146 }
147
148 static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
149 const char *p;
150 int r;
151
152 r = sd_bus_message_open_container(m, 'r', "sv");
153 if (r < 0)
154 return bus_log_create_error(r);
155
156 r = sd_bus_message_append_basic(m, 's', field);
157 if (r < 0)
158 return bus_log_create_error(r);
159
160 r = sd_bus_message_open_container(m, 'v', "as");
161 if (r < 0)
162 return bus_log_create_error(r);
163
164 r = sd_bus_message_open_container(m, 'a', "s");
165 if (r < 0)
166 return bus_log_create_error(r);
167
168 for (p = eq;;) {
169 _cleanup_free_ char *word = NULL;
170
171 r = extract_first_word(&p, &word, NULL, flags);
172 if (r == 0)
173 break;
174 if (r == -ENOMEM)
175 return log_oom();
176 if (r < 0)
177 return log_error_errno(r, "Invalid syntax: %s", eq);
178
179 r = sd_bus_message_append_basic(m, 's', word);
180 if (r < 0)
181 return bus_log_create_error(r);
182 }
183
184 r = sd_bus_message_close_container(m);
185 if (r < 0)
186 return bus_log_create_error(r);
187
188 r = sd_bus_message_close_container(m);
189 if (r < 0)
190 return bus_log_create_error(r);
191
192 r = sd_bus_message_close_container(m);
193 if (r < 0)
194 return bus_log_create_error(r);
195
196 return 1;
197 }
198
199 static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
200 int r;
201
202 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
203 if (r < 0)
204 return bus_log_create_error(r);
205
206 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
207 if (r < 0)
208 return bus_log_create_error(r);
209
210 r = sd_bus_message_open_container(m, 'v', "ay");
211 if (r < 0)
212 return bus_log_create_error(r);
213
214 r = sd_bus_message_append_array(m, 'y', buf, n);
215 if (r < 0)
216 return bus_log_create_error(r);
217
218 r = sd_bus_message_close_container(m);
219 if (r < 0)
220 return bus_log_create_error(r);
221
222 r = sd_bus_message_close_container(m);
223 if (r < 0)
224 return bus_log_create_error(r);
225
226 return 1;
227 }
228
229 static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
230 char *n;
231 usec_t t;
232 size_t l;
233 int r;
234
235 r = parse_sec(eq, &t);
236 if (r < 0)
237 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
238
239 l = strlen(field);
240 n = newa(char, l + 2);
241 /* Change suffix Sec → USec */
242 strcpy(mempcpy(n, field, l - 3), "USec");
243
244 r = sd_bus_message_append(m, "(sv)", n, "t", t);
245 if (r < 0)
246 return bus_log_create_error(r);
247
248 return 1;
249 }
250
251 static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
252 uint64_t v;
253 int r;
254
255 r = parse_size(eq, base, &v);
256 if (r < 0)
257 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
258
259 r = sd_bus_message_append(m, "(sv)", field, "t", v);
260 if (r < 0)
261 return bus_log_create_error(r);
262
263 return 1;
264 }
265
266 static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
267 bool explicit_path = false, done = false;
268 _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
269 _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
270 ExecCommandFlags flags = 0;
271 bool is_ex_prop = endswith(field, "Ex");
272 int r;
273
274 do {
275 switch (*eq) {
276
277 case '-':
278 if (FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE))
279 done = true;
280 else {
281 flags |= EXEC_COMMAND_IGNORE_FAILURE;
282 eq++;
283 }
284 break;
285
286 case '@':
287 if (explicit_path)
288 done = true;
289 else {
290 explicit_path = true;
291 eq++;
292 }
293 break;
294
295 case ':':
296 if (FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND))
297 done = true;
298 else {
299 flags |= EXEC_COMMAND_NO_ENV_EXPAND;
300 eq++;
301 }
302 break;
303
304 case '+':
305 if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))
306 done = true;
307 else {
308 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
309 eq++;
310 }
311 break;
312
313 case '!':
314 if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))
315 done = true;
316 else if (FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)) {
317 flags &= ~EXEC_COMMAND_NO_SETUID;
318 flags |= EXEC_COMMAND_AMBIENT_MAGIC;
319 eq++;
320 } else {
321 flags |= EXEC_COMMAND_NO_SETUID;
322 eq++;
323 }
324 break;
325
326 default:
327 done = true;
328 break;
329 }
330 } while (!done);
331
332 if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))) {
333 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
334 is_ex_prop = true;
335 upgraded_name = strjoin(field, "Ex");
336 if (!upgraded_name)
337 return log_oom();
338 }
339
340 if (is_ex_prop) {
341 r = exec_command_flags_to_strv(flags, &ex_opts);
342 if (r < 0)
343 return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
344 }
345
346 if (explicit_path) {
347 r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
348 if (r < 0)
349 return log_error_errno(r, "Failed to parse path: %m");
350 }
351
352 r = strv_split_full(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
353 if (r < 0)
354 return log_error_errno(r, "Failed to parse command line: %m");
355
356 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
357 if (r < 0)
358 return bus_log_create_error(r);
359
360 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, upgraded_name ?: field);
361 if (r < 0)
362 return bus_log_create_error(r);
363
364 r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
365 if (r < 0)
366 return bus_log_create_error(r);
367
368 r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
369 if (r < 0)
370 return bus_log_create_error(r);
371
372 if (!strv_isempty(l)) {
373
374 r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
375 if (r < 0)
376 return bus_log_create_error(r);
377
378 r = sd_bus_message_append(m, "s", path ?: l[0]);
379 if (r < 0)
380 return bus_log_create_error(r);
381
382 r = sd_bus_message_append_strv(m, l);
383 if (r < 0)
384 return bus_log_create_error(r);
385
386 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));
387 if (r < 0)
388 return bus_log_create_error(r);
389
390 r = sd_bus_message_close_container(m);
391 if (r < 0)
392 return bus_log_create_error(r);
393 }
394
395 r = sd_bus_message_close_container(m);
396 if (r < 0)
397 return bus_log_create_error(r);
398
399 r = sd_bus_message_close_container(m);
400 if (r < 0)
401 return bus_log_create_error(r);
402
403 r = sd_bus_message_close_container(m);
404 if (r < 0)
405 return bus_log_create_error(r);
406
407 return 1;
408 }
409
410 static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
411 int r;
412
413 assert(m);
414 assert(prefix);
415
416 r = sd_bus_message_open_container(m, 'r', "iayu");
417 if (r < 0)
418 return r;
419
420 r = sd_bus_message_append(m, "i", family);
421 if (r < 0)
422 return r;
423
424 r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
425 if (r < 0)
426 return r;
427
428 r = sd_bus_message_append(m, "u", prefixlen);
429 if (r < 0)
430 return r;
431
432 return sd_bus_message_close_container(m);
433 }
434
435 static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
436 int r;
437
438 if (STR_IN_SET(field, "DevicePolicy",
439 "Slice",
440 "ManagedOOMSwap",
441 "ManagedOOMMemoryPressure",
442 "ManagedOOMPreference"))
443 return bus_append_string(m, field, eq);
444
445 if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
446 r = parse_permyriad(eq);
447 if (r < 0)
448 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
449
450 /* Pass around scaled to 2^32-1 == 100% */
451 r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
452 if (r < 0)
453 return bus_log_create_error(r);
454
455 return 1;
456 }
457
458 if (STR_IN_SET(field, "CPUAccounting",
459 "MemoryAccounting",
460 "IOAccounting",
461 "BlockIOAccounting",
462 "TasksAccounting",
463 "IPAccounting"))
464 return bus_append_parse_boolean(m, field, eq);
465
466 if (STR_IN_SET(field, "CPUWeight",
467 "StartupCPUWeight",
468 "IOWeight",
469 "StartupIOWeight"))
470 return bus_append_cg_weight_parse(m, field, eq);
471
472 if (STR_IN_SET(field, "CPUShares",
473 "StartupCPUShares"))
474 return bus_append_cg_cpu_shares_parse(m, field, eq);
475
476 if (STR_IN_SET(field, "AllowedCPUs",
477 "AllowedMemoryNodes")) {
478 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
479 _cleanup_free_ uint8_t *array = NULL;
480 size_t allocated;
481
482 r = parse_cpu_set(eq, &cpuset);
483 if (r < 0)
484 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
485
486 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
487 if (r < 0)
488 return log_error_errno(r, "Failed to serialize CPUSet: %m");
489
490 return bus_append_byte_array(m, field, array, allocated);
491 }
492
493 if (STR_IN_SET(field, "BlockIOWeight",
494 "StartupBlockIOWeight"))
495 return bus_append_cg_blkio_weight_parse(m, field, eq);
496
497 if (streq(field, "DisableControllers"))
498 return bus_append_strv(m, "DisableControllers", eq, EXTRACT_UNQUOTE);
499
500 if (streq(field, "Delegate")) {
501 r = parse_boolean(eq);
502 if (r < 0)
503 return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_UNQUOTE);
504
505 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
506 if (r < 0)
507 return bus_log_create_error(r);
508
509 return 1;
510 }
511
512 if (STR_IN_SET(field, "MemoryMin",
513 "DefaultMemoryLow",
514 "DefaultMemoryMin",
515 "MemoryLow",
516 "MemoryHigh",
517 "MemoryMax",
518 "MemorySwapMax",
519 "MemoryLimit",
520 "TasksMax")) {
521
522 if (streq(eq, "infinity")) {
523 r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
524 if (r < 0)
525 return bus_log_create_error(r);
526 return 1;
527 } else if (isempty(eq)) {
528 uint64_t empty_value = STR_IN_SET(field,
529 "DefaultMemoryLow",
530 "DefaultMemoryMin",
531 "MemoryLow",
532 "MemoryMin") ?
533 CGROUP_LIMIT_MIN :
534 CGROUP_LIMIT_MAX;
535
536 r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
537 if (r < 0)
538 return bus_log_create_error(r);
539 return 1;
540 }
541
542 r = parse_permyriad(eq);
543 if (r >= 0) {
544 char *n;
545
546 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
547 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
548 * size can be determined server-side. */
549
550 n = strjoina(field, "Scale");
551 r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
552 if (r < 0)
553 return bus_log_create_error(r);
554
555 return 1;
556 }
557
558 if (streq(field, "TasksMax"))
559 return bus_append_safe_atou64(m, field, eq);
560
561 return bus_append_parse_size(m, field, eq, 1024);
562 }
563
564 if (streq(field, "CPUQuota")) {
565 if (isempty(eq))
566 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
567 else {
568 r = parse_permyriad_unbounded(eq);
569 if (r == 0)
570 return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
571 "CPU quota too small.");
572 if (r < 0)
573 return log_error_errno(r, "CPU quota '%s' invalid.", eq);
574
575 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
576 }
577
578 if (r < 0)
579 return bus_log_create_error(r);
580
581 return 1;
582 }
583
584 if (streq(field, "CPUQuotaPeriodSec")) {
585 usec_t u = USEC_INFINITY;
586
587 r = parse_sec_def_infinity(eq, &u);
588 if (r < 0)
589 return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
590
591 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
592 if (r < 0)
593 return bus_log_create_error(r);
594
595 return 1;
596 }
597
598 if (streq(field, "DeviceAllow")) {
599 if (isempty(eq))
600 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
601 else {
602 const char *path = eq, *rwm = NULL, *e;
603
604 e = strchr(eq, ' ');
605 if (e) {
606 path = strndupa(eq, e - eq);
607 rwm = e+1;
608 }
609
610 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
611 }
612
613 if (r < 0)
614 return bus_log_create_error(r);
615
616 return 1;
617 }
618
619 if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
620 if (isempty(eq))
621 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
622 else {
623 const char *path, *bandwidth, *e;
624 uint64_t bytes;
625
626 e = strchr(eq, ' ');
627 if (!e)
628 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
629 "Failed to parse %s value %s.",
630 field, eq);
631
632 path = strndupa(eq, e - eq);
633 bandwidth = e+1;
634
635 if (streq(bandwidth, "infinity"))
636 bytes = CGROUP_LIMIT_MAX;
637 else {
638 r = parse_size(bandwidth, 1000, &bytes);
639 if (r < 0)
640 return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
641 }
642
643 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
644 }
645
646 if (r < 0)
647 return bus_log_create_error(r);
648
649 return 1;
650 }
651
652 if (STR_IN_SET(field, "IODeviceWeight",
653 "BlockIODeviceWeight")) {
654 if (isempty(eq))
655 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
656 else {
657 const char *path, *weight, *e;
658 uint64_t u;
659
660 e = strchr(eq, ' ');
661 if (!e)
662 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
663 "Failed to parse %s value %s.",
664 field, eq);
665
666 path = strndupa(eq, e - eq);
667 weight = e+1;
668
669 r = safe_atou64(weight, &u);
670 if (r < 0)
671 return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
672
673 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
674 }
675
676 if (r < 0)
677 return bus_log_create_error(r);
678
679 return 1;
680 }
681
682 if (streq(field, "IODeviceLatencyTargetSec")) {
683 const char *field_usec = "IODeviceLatencyTargetUSec";
684
685 if (isempty(eq))
686 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
687 else {
688 const char *path, *target, *e;
689 usec_t usec;
690
691 e = strchr(eq, ' ');
692 if (!e)
693 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
694 "Failed to parse %s value %s.",
695 field, eq);
696
697 path = strndupa(eq, e - eq);
698 target = e+1;
699
700 r = parse_sec(target, &usec);
701 if (r < 0)
702 return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
703
704 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
705 }
706
707 if (r < 0)
708 return bus_log_create_error(r);
709
710 return 1;
711 }
712
713 if (STR_IN_SET(field, "IPAddressAllow",
714 "IPAddressDeny")) {
715 unsigned char prefixlen;
716 union in_addr_union prefix = {};
717 int family;
718
719 if (isempty(eq)) {
720 r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
721 if (r < 0)
722 return bus_log_create_error(r);
723
724 return 1;
725 }
726
727 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
728 if (r < 0)
729 return bus_log_create_error(r);
730
731 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
732 if (r < 0)
733 return bus_log_create_error(r);
734
735 r = sd_bus_message_open_container(m, 'v', "a(iayu)");
736 if (r < 0)
737 return bus_log_create_error(r);
738
739 r = sd_bus_message_open_container(m, 'a', "(iayu)");
740 if (r < 0)
741 return bus_log_create_error(r);
742
743 if (streq(eq, "any")) {
744 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
745
746 r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
747 if (r < 0)
748 return bus_log_create_error(r);
749
750 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
751 if (r < 0)
752 return bus_log_create_error(r);
753
754 } else if (is_localhost(eq)) {
755 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
756
757 prefix.in.s_addr = htobe32(0x7f000000);
758 r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
759 if (r < 0)
760 return bus_log_create_error(r);
761
762 prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
763 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
764 if (r < 0)
765 return r;
766
767 } else if (streq(eq, "link-local")) {
768 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
769
770 prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
771 r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
772 if (r < 0)
773 return bus_log_create_error(r);
774
775 prefix.in6 = (struct in6_addr) {
776 .s6_addr32[0] = htobe32(0xfe800000)
777 };
778 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
779 if (r < 0)
780 return bus_log_create_error(r);
781
782 } else if (streq(eq, "multicast")) {
783 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
784
785 prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
786 r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
787 if (r < 0)
788 return bus_log_create_error(r);
789
790 prefix.in6 = (struct in6_addr) {
791 .s6_addr32[0] = htobe32(0xff000000)
792 };
793 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
794 if (r < 0)
795 return bus_log_create_error(r);
796
797 } else {
798 for (;;) {
799 _cleanup_free_ char *word = NULL;
800
801 r = extract_first_word(&eq, &word, NULL, 0);
802 if (r == 0)
803 break;
804 if (r == -ENOMEM)
805 return log_oom();
806 if (r < 0)
807 return log_error_errno(r, "Failed to parse %s: %s", field, eq);
808
809 r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
810 if (r < 0)
811 return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
812
813 r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
814 if (r < 0)
815 return bus_log_create_error(r);
816 }
817 }
818
819 r = sd_bus_message_close_container(m);
820 if (r < 0)
821 return bus_log_create_error(r);
822
823 r = sd_bus_message_close_container(m);
824 if (r < 0)
825 return bus_log_create_error(r);
826
827 r = sd_bus_message_close_container(m);
828 if (r < 0)
829 return bus_log_create_error(r);
830
831 return 1;
832 }
833
834 if (STR_IN_SET(field, "IPIngressFilterPath",
835 "IPEgressFilterPath")) {
836 if (isempty(eq))
837 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
838 else
839 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
840
841 if (r < 0)
842 return bus_log_create_error(r);
843
844 return 1;
845 }
846
847 if (streq(field, "BPFProgram")) {
848 if (isempty(eq))
849 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
850 else {
851 _cleanup_free_ char *word = NULL;
852
853 r = extract_first_word(&eq, &word, ":", 0);
854 if (r == -ENOMEM)
855 return log_oom();
856 if (r < 0)
857 return log_error_errno(r, "Failed to parse %s: %m", field);
858
859 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
860 }
861 if (r < 0)
862 return bus_log_create_error(r);
863
864 return 1;
865 }
866
867 if (STR_IN_SET(field, "SocketBindAllow",
868 "SocketBindDeny")) {
869 if (isempty(eq))
870 r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
871 else {
872 int32_t family, ip_protocol;
873 uint16_t nr_ports, port_min;
874
875 r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
876 if (r == -ENOMEM)
877 return log_oom();
878 if (r < 0)
879 return log_error_errno(r, "Failed to parse %s", field);
880
881 r = sd_bus_message_append(
882 m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
883 }
884 if (r < 0)
885 return bus_log_create_error(r);
886
887 return 1;
888 }
889
890 return 0;
891 }
892
893 static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
894 if (streq(field, "Where"))
895 return bus_append_string(m, field, eq);
896
897 if (streq(field, "DirectoryMode"))
898 return bus_append_parse_mode(m, field, eq);
899
900 if (streq(field, "TimeoutIdleSec"))
901 return bus_append_parse_sec_rename(m, field, eq);
902
903 return 0;
904 }
905
906 static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
907 const char *suffix;
908 int r;
909
910 if (STR_IN_SET(field, "User",
911 "Group",
912 "UtmpIdentifier",
913 "UtmpMode",
914 "PAMName",
915 "TTYPath",
916 "WorkingDirectory",
917 "RootDirectory",
918 "SyslogIdentifier",
919 "ProtectSystem",
920 "ProtectHome",
921 "SELinuxContext",
922 "RootImage",
923 "RootVerity",
924 "RuntimeDirectoryPreserve",
925 "Personality",
926 "KeyringMode",
927 "ProtectProc",
928 "ProcSubset",
929 "NetworkNamespacePath",
930 "IPCNamespacePath",
931 "LogNamespace"))
932 return bus_append_string(m, field, eq);
933
934 if (STR_IN_SET(field, "IgnoreSIGPIPE",
935 "TTYVHangup",
936 "TTYReset",
937 "TTYVTDisallocate",
938 "PrivateTmp",
939 "PrivateDevices",
940 "PrivateNetwork",
941 "PrivateUsers",
942 "PrivateMounts",
943 "PrivateIPC",
944 "NoNewPrivileges",
945 "SyslogLevelPrefix",
946 "MemoryDenyWriteExecute",
947 "RestrictRealtime",
948 "DynamicUser",
949 "RemoveIPC",
950 "ProtectKernelTunables",
951 "ProtectKernelModules",
952 "ProtectKernelLogs",
953 "ProtectClock",
954 "ProtectControlGroups",
955 "MountAPIVFS",
956 "CPUSchedulingResetOnFork",
957 "LockPersonality",
958 "ProtectHostname",
959 "RestrictSUIDSGID"))
960 return bus_append_parse_boolean(m, field, eq);
961
962 if (STR_IN_SET(field, "ReadWriteDirectories",
963 "ReadOnlyDirectories",
964 "InaccessibleDirectories",
965 "ReadWritePaths",
966 "ReadOnlyPaths",
967 "InaccessiblePaths",
968 "ExecPaths",
969 "NoExecPaths",
970 "RuntimeDirectory",
971 "StateDirectory",
972 "CacheDirectory",
973 "LogsDirectory",
974 "ConfigurationDirectory",
975 "SupplementaryGroups",
976 "SystemCallArchitectures"))
977 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
978
979 if (STR_IN_SET(field, "SyslogLevel",
980 "LogLevelMax"))
981 return bus_append_log_level_from_string(m, field, eq);
982
983 if (streq(field, "SyslogFacility"))
984 return bus_append_log_facility_unshifted_from_string(m, field, eq);
985
986 if (streq(field, "SecureBits"))
987 return bus_append_secure_bits_from_string(m, field, eq);
988
989 if (streq(field, "CPUSchedulingPolicy"))
990 return bus_append_sched_policy_from_string(m, field, eq);
991
992 if (STR_IN_SET(field, "CPUSchedulingPriority",
993 "OOMScoreAdjust"))
994 return bus_append_safe_atoi(m, field, eq);
995
996 if (streq(field, "CoredumpFilter"))
997 return bus_append_coredump_filter_mask_from_string(m, field, eq);
998
999 if (streq(field, "Nice"))
1000 return bus_append_parse_nice(m, field, eq);
1001
1002 if (streq(field, "SystemCallErrorNumber"))
1003 return bus_append_seccomp_parse_errno_or_action(m, field, eq);
1004
1005 if (streq(field, "IOSchedulingClass"))
1006 return bus_append_ioprio_class_from_string(m, field, eq);
1007
1008 if (streq(field, "IOSchedulingPriority"))
1009 return bus_append_ioprio_parse_priority(m, field, eq);
1010
1011 if (STR_IN_SET(field, "RuntimeDirectoryMode",
1012 "StateDirectoryMode",
1013 "CacheDirectoryMode",
1014 "LogsDirectoryMode",
1015 "ConfigurationDirectoryMode",
1016 "UMask"))
1017 return bus_append_parse_mode(m, field, eq);
1018
1019 if (streq(field, "TimerSlackNSec"))
1020 return bus_append_parse_nsec(m, field, eq);
1021
1022 if (streq(field, "LogRateLimitIntervalSec"))
1023 return bus_append_parse_sec_rename(m, field, eq);
1024
1025 if (streq(field, "LogRateLimitBurst"))
1026 return bus_append_safe_atou(m, field, eq);
1027
1028 if (streq(field, "MountFlags"))
1029 return bus_append_mount_propagation_flags_from_string(m, field, eq);
1030
1031 if (STR_IN_SET(field, "Environment",
1032 "UnsetEnvironment",
1033 "PassEnvironment"))
1034 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
1035
1036 if (streq(field, "EnvironmentFile")) {
1037 if (isempty(eq))
1038 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1039 else
1040 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1041 eq[0] == '-' ? eq + 1 : eq,
1042 eq[0] == '-');
1043 if (r < 0)
1044 return bus_log_create_error(r);
1045
1046 return 1;
1047 }
1048
1049 if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
1050 r = sd_bus_message_open_container(m, 'r', "sv");
1051 if (r < 0)
1052 return bus_log_create_error(r);
1053
1054 r = sd_bus_message_append_basic(m, 's', field);
1055 if (r < 0)
1056 return bus_log_create_error(r);
1057
1058 r = sd_bus_message_open_container(m, 'v', "a(say)");
1059 if (r < 0)
1060 return bus_log_create_error(r);
1061
1062 if (isempty(eq))
1063 r = sd_bus_message_append(m, "a(say)", 0);
1064 else {
1065 _cleanup_free_ char *word = NULL;
1066 const char *p = eq;
1067
1068 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1069 if (r == -ENOMEM)
1070 return log_oom();
1071 if (r < 0)
1072 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
1073 if (r == 0 || !p)
1074 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
1075
1076 r = sd_bus_message_open_container(m, 'a', "(say)");
1077 if (r < 0)
1078 return bus_log_create_error(r);
1079
1080 r = sd_bus_message_open_container(m, 'r', "say");
1081 if (r < 0)
1082 return bus_log_create_error(r);
1083
1084 r = sd_bus_message_append(m, "s", word);
1085 if (r < 0)
1086 return bus_log_create_error(r);
1087
1088 if (streq(field, "SetCredentialEncrypted")) {
1089 _cleanup_free_ void *decoded = NULL;
1090 size_t decoded_size;
1091
1092 r = unbase64mem(p, SIZE_MAX, &decoded, &decoded_size);
1093 if (r < 0)
1094 return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
1095
1096 r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
1097 } else {
1098 _cleanup_free_ char *unescaped = NULL;
1099 ssize_t l;
1100
1101 l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
1102 if (l < 0)
1103 return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
1104
1105 r = sd_bus_message_append_array(m, 'y', unescaped, l);
1106 }
1107 if (r < 0)
1108 return bus_log_create_error(r);
1109
1110 r = sd_bus_message_close_container(m);
1111 if (r < 0)
1112 return bus_log_create_error(r);
1113
1114 r = sd_bus_message_close_container(m);
1115 }
1116 if (r < 0)
1117 return bus_log_create_error(r);
1118
1119 r = sd_bus_message_close_container(m);
1120 if (r < 0)
1121 return bus_log_create_error(r);
1122
1123 r = sd_bus_message_close_container(m);
1124 if (r < 0)
1125 return bus_log_create_error(r);
1126
1127 return 1;
1128 }
1129
1130 if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
1131 r = sd_bus_message_open_container(m, 'r', "sv");
1132 if (r < 0)
1133 return bus_log_create_error(r);
1134
1135 r = sd_bus_message_append_basic(m, 's', field);
1136 if (r < 0)
1137 return bus_log_create_error(r);
1138
1139 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1140 if (r < 0)
1141 return bus_log_create_error(r);
1142
1143 if (isempty(eq))
1144 r = sd_bus_message_append(m, "a(ss)", 0);
1145 else {
1146 _cleanup_free_ char *word = NULL;
1147 const char *p = eq;
1148
1149 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1150 if (r == -ENOMEM)
1151 return log_oom();
1152 if (r < 0)
1153 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
1154 if (r == 0 || !p)
1155 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
1156
1157 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1158 }
1159 if (r < 0)
1160 return bus_log_create_error(r);
1161
1162 r = sd_bus_message_close_container(m);
1163 if (r < 0)
1164 return bus_log_create_error(r);
1165
1166 r = sd_bus_message_close_container(m);
1167 if (r < 0)
1168 return bus_log_create_error(r);
1169
1170 return 1;
1171 }
1172
1173 if (streq(field, "LogExtraFields")) {
1174 r = sd_bus_message_open_container(m, 'r', "sv");
1175 if (r < 0)
1176 return bus_log_create_error(r);
1177
1178 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
1179 if (r < 0)
1180 return bus_log_create_error(r);
1181
1182 r = sd_bus_message_open_container(m, 'v', "aay");
1183 if (r < 0)
1184 return bus_log_create_error(r);
1185
1186 r = sd_bus_message_open_container(m, 'a', "ay");
1187 if (r < 0)
1188 return bus_log_create_error(r);
1189
1190 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
1191 if (r < 0)
1192 return bus_log_create_error(r);
1193
1194 r = sd_bus_message_close_container(m);
1195 if (r < 0)
1196 return bus_log_create_error(r);
1197
1198 r = sd_bus_message_close_container(m);
1199 if (r < 0)
1200 return bus_log_create_error(r);
1201
1202 r = sd_bus_message_close_container(m);
1203 if (r < 0)
1204 return bus_log_create_error(r);
1205
1206 return 1;
1207 }
1208
1209 if (STR_IN_SET(field, "StandardInput",
1210 "StandardOutput",
1211 "StandardError")) {
1212 const char *n, *appended;
1213
1214 if ((n = startswith(eq, "fd:"))) {
1215 appended = strjoina(field, "FileDescriptorName");
1216 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1217 } else if ((n = startswith(eq, "file:"))) {
1218 appended = strjoina(field, "File");
1219 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1220 } else if ((n = startswith(eq, "append:"))) {
1221 appended = strjoina(field, "FileToAppend");
1222 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1223 } else if ((n = startswith(eq, "truncate:"))) {
1224 appended = strjoina(field, "FileToTruncate");
1225 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1226 } else
1227 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
1228 if (r < 0)
1229 return bus_log_create_error(r);
1230
1231 return 1;
1232 }
1233
1234 if (streq(field, "StandardInputText")) {
1235 _cleanup_free_ char *unescaped = NULL;
1236 ssize_t l;
1237
1238 l = cunescape(eq, 0, &unescaped);
1239 if (l < 0)
1240 return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
1241
1242 if (!strextend(&unescaped, "\n"))
1243 return log_oom();
1244
1245 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1246 * programmatic interface anyway */
1247
1248 return bus_append_byte_array(m, field, unescaped, l + 1);
1249 }
1250
1251 if (streq(field, "StandardInputData")) {
1252 _cleanup_free_ void *decoded = NULL;
1253 size_t sz;
1254
1255 r = unbase64mem(eq, SIZE_MAX, &decoded, &sz);
1256 if (r < 0)
1257 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
1258
1259 return bus_append_byte_array(m, field, decoded, sz);
1260 }
1261
1262 if ((suffix = startswith(field, "Limit"))) {
1263 int rl;
1264
1265 rl = rlimit_from_string(suffix);
1266 if (rl >= 0) {
1267 const char *sn;
1268 struct rlimit l;
1269
1270 r = rlimit_parse(rl, eq, &l);
1271 if (r < 0)
1272 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
1273
1274 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
1275 if (r < 0)
1276 return bus_log_create_error(r);
1277
1278 sn = strjoina(field, "Soft");
1279 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
1280 if (r < 0)
1281 return bus_log_create_error(r);
1282
1283 return 1;
1284 }
1285 }
1286
1287 if (STR_IN_SET(field, "AppArmorProfile",
1288 "SmackProcessLabel")) {
1289 int ignore = 0;
1290 const char *s = eq;
1291
1292 if (eq[0] == '-') {
1293 ignore = 1;
1294 s = eq + 1;
1295 }
1296
1297 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
1298 if (r < 0)
1299 return bus_log_create_error(r);
1300
1301 return 1;
1302 }
1303
1304 if (STR_IN_SET(field, "CapabilityBoundingSet",
1305 "AmbientCapabilities")) {
1306 uint64_t sum = 0;
1307 bool invert = false;
1308 const char *p = eq;
1309
1310 if (*p == '~') {
1311 invert = true;
1312 p++;
1313 }
1314
1315 r = capability_set_from_string(p, &sum);
1316 if (r < 0)
1317 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
1318
1319 sum = invert ? ~sum : sum;
1320
1321 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
1322 if (r < 0)
1323 return bus_log_create_error(r);
1324
1325 return 1;
1326 }
1327
1328 if (streq(field, "CPUAffinity")) {
1329 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
1330 _cleanup_free_ uint8_t *array = NULL;
1331 size_t allocated;
1332
1333 if (eq && streq(eq, "numa")) {
1334 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1335 if (r < 0)
1336 return bus_log_create_error(r);
1337 return r;
1338 }
1339
1340 r = parse_cpu_set(eq, &cpuset);
1341 if (r < 0)
1342 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1343
1344 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1345 if (r < 0)
1346 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1347
1348 return bus_append_byte_array(m, field, array, allocated);
1349 }
1350
1351 if (streq(field, "NUMAPolicy")) {
1352 r = mpol_from_string(eq);
1353 if (r < 0)
1354 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1355
1356 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1357 if (r < 0)
1358 return bus_log_create_error(r);
1359
1360 return 1;
1361 }
1362
1363 if (streq(field, "NUMAMask")) {
1364 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1365 _cleanup_free_ uint8_t *array = NULL;
1366 size_t allocated;
1367
1368 if (eq && streq(eq, "all")) {
1369 r = numa_mask_add_all(&nodes);
1370 if (r < 0)
1371 return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1372 } else {
1373 r = parse_cpu_set(eq, &nodes);
1374 if (r < 0)
1375 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1376 }
1377
1378 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1379 if (r < 0)
1380 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1381
1382 return bus_append_byte_array(m, field, array, allocated);
1383 }
1384
1385 if (STR_IN_SET(field, "RestrictAddressFamilies",
1386 "SystemCallFilter",
1387 "SystemCallLog")) {
1388 int allow_list = 1;
1389 const char *p = eq;
1390
1391 if (*p == '~') {
1392 allow_list = 0;
1393 p++;
1394 }
1395
1396 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1397 if (r < 0)
1398 return bus_log_create_error(r);
1399
1400 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1401 if (r < 0)
1402 return bus_log_create_error(r);
1403
1404 r = sd_bus_message_open_container(m, 'v', "(bas)");
1405 if (r < 0)
1406 return bus_log_create_error(r);
1407
1408 r = sd_bus_message_open_container(m, 'r', "bas");
1409 if (r < 0)
1410 return bus_log_create_error(r);
1411
1412 r = sd_bus_message_append_basic(m, 'b', &allow_list);
1413 if (r < 0)
1414 return bus_log_create_error(r);
1415
1416 r = sd_bus_message_open_container(m, 'a', "s");
1417 if (r < 0)
1418 return bus_log_create_error(r);
1419
1420 for (;;) {
1421 _cleanup_free_ char *word = NULL;
1422
1423 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1424 if (r == 0)
1425 break;
1426 if (r == -ENOMEM)
1427 return log_oom();
1428 if (r < 0)
1429 return log_error_errno(r, "Invalid syntax: %s", eq);
1430
1431 r = sd_bus_message_append_basic(m, 's', word);
1432 if (r < 0)
1433 return bus_log_create_error(r);
1434 }
1435
1436 r = sd_bus_message_close_container(m);
1437 if (r < 0)
1438 return bus_log_create_error(r);
1439
1440 r = sd_bus_message_close_container(m);
1441 if (r < 0)
1442 return bus_log_create_error(r);
1443
1444 r = sd_bus_message_close_container(m);
1445 if (r < 0)
1446 return bus_log_create_error(r);
1447
1448 r = sd_bus_message_close_container(m);
1449 if (r < 0)
1450 return bus_log_create_error(r);
1451
1452 return 1;
1453 }
1454
1455 if (streq(field, "RestrictNamespaces")) {
1456 bool invert = false;
1457 unsigned long flags;
1458
1459 r = parse_boolean(eq);
1460 if (r > 0)
1461 flags = 0;
1462 else if (r == 0)
1463 flags = NAMESPACE_FLAGS_ALL;
1464 else {
1465 if (eq[0] == '~') {
1466 invert = true;
1467 eq++;
1468 }
1469
1470 r = namespace_flags_from_string(eq, &flags);
1471 if (r < 0)
1472 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1473 }
1474
1475 if (invert)
1476 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1477
1478 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1479 if (r < 0)
1480 return bus_log_create_error(r);
1481
1482 return 1;
1483 }
1484
1485 if (STR_IN_SET(field, "BindPaths",
1486 "BindReadOnlyPaths")) {
1487 const char *p = eq;
1488
1489 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1490 if (r < 0)
1491 return bus_log_create_error(r);
1492
1493 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1494 if (r < 0)
1495 return bus_log_create_error(r);
1496
1497 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1498 if (r < 0)
1499 return bus_log_create_error(r);
1500
1501 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1502 if (r < 0)
1503 return bus_log_create_error(r);
1504
1505 for (;;) {
1506 _cleanup_free_ char *source = NULL, *destination = NULL;
1507 char *s = NULL, *d = NULL;
1508 bool ignore_enoent = false;
1509 uint64_t flags = MS_REC;
1510
1511 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1512 if (r < 0)
1513 return log_error_errno(r, "Failed to parse argument: %m");
1514 if (r == 0)
1515 break;
1516
1517 s = source;
1518 if (s[0] == '-') {
1519 ignore_enoent = true;
1520 s++;
1521 }
1522
1523 if (p && p[-1] == ':') {
1524 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1525 if (r < 0)
1526 return log_error_errno(r, "Failed to parse argument: %m");
1527 if (r == 0)
1528 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1529 "Missing argument after ':': %s",
1530 eq);
1531
1532 d = destination;
1533
1534 if (p && p[-1] == ':') {
1535 _cleanup_free_ char *options = NULL;
1536
1537 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
1538 if (r < 0)
1539 return log_error_errno(r, "Failed to parse argument: %m");
1540
1541 if (isempty(options) || streq(options, "rbind"))
1542 flags = MS_REC;
1543 else if (streq(options, "norbind"))
1544 flags = 0;
1545 else
1546 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1547 "Unknown options: %s",
1548 eq);
1549 }
1550 } else
1551 d = s;
1552
1553 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1554 if (r < 0)
1555 return bus_log_create_error(r);
1556 }
1557
1558 r = sd_bus_message_close_container(m);
1559 if (r < 0)
1560 return bus_log_create_error(r);
1561
1562 r = sd_bus_message_close_container(m);
1563 if (r < 0)
1564 return bus_log_create_error(r);
1565
1566 r = sd_bus_message_close_container(m);
1567 if (r < 0)
1568 return bus_log_create_error(r);
1569
1570 return 1;
1571 }
1572
1573 if (streq(field, "TemporaryFileSystem")) {
1574 const char *p = eq;
1575
1576 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1577 if (r < 0)
1578 return bus_log_create_error(r);
1579
1580 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1581 if (r < 0)
1582 return bus_log_create_error(r);
1583
1584 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1585 if (r < 0)
1586 return bus_log_create_error(r);
1587
1588 r = sd_bus_message_open_container(m, 'a', "(ss)");
1589 if (r < 0)
1590 return bus_log_create_error(r);
1591
1592 for (;;) {
1593 _cleanup_free_ char *word = NULL, *path = NULL;
1594 const char *w;
1595
1596 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1597 if (r < 0)
1598 return log_error_errno(r, "Failed to parse argument: %m");
1599 if (r == 0)
1600 break;
1601
1602 w = word;
1603 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1604 if (r < 0)
1605 return log_error_errno(r, "Failed to parse argument: %m");
1606 if (r == 0)
1607 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1608 "Failed to parse argument: %s",
1609 p);
1610
1611 r = sd_bus_message_append(m, "(ss)", path, w);
1612 if (r < 0)
1613 return bus_log_create_error(r);
1614 }
1615
1616 r = sd_bus_message_close_container(m);
1617 if (r < 0)
1618 return bus_log_create_error(r);
1619
1620 r = sd_bus_message_close_container(m);
1621 if (r < 0)
1622 return bus_log_create_error(r);
1623
1624 r = sd_bus_message_close_container(m);
1625 if (r < 0)
1626 return bus_log_create_error(r);
1627
1628 return 1;
1629 }
1630
1631 if (streq(field, "RootHash")) {
1632 _cleanup_free_ void *roothash_decoded = NULL;
1633 size_t roothash_decoded_size = 0;
1634
1635 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1636 if (path_is_absolute(eq))
1637 return bus_append_string(m, "RootHashPath", eq);
1638
1639 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1640 r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
1641 if (r < 0)
1642 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1643 if (roothash_decoded_size < sizeof(sd_id128_t))
1644 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
1645
1646 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1647 }
1648
1649 if (streq(field, "RootHashSignature")) {
1650 _cleanup_free_ void *roothash_sig_decoded = NULL;
1651 char *value;
1652 size_t roothash_sig_decoded_size = 0;
1653
1654 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1655 if (path_is_absolute(eq))
1656 return bus_append_string(m, "RootHashSignaturePath", eq);
1657
1658 if (!(value = startswith(eq, "base64:")))
1659 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
1660
1661 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1662 r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
1663 if (r < 0)
1664 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1665
1666 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1667 }
1668
1669 if (streq(field, "RootImageOptions")) {
1670 _cleanup_strv_free_ char **l = NULL;
1671 char **first = NULL, **second = NULL;
1672 const char *p = eq;
1673
1674 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1675 if (r < 0)
1676 return bus_log_create_error(r);
1677
1678 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1679 if (r < 0)
1680 return bus_log_create_error(r);
1681
1682 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1683 if (r < 0)
1684 return bus_log_create_error(r);
1685
1686 r = sd_bus_message_open_container(m, 'a', "(ss)");
1687 if (r < 0)
1688 return bus_log_create_error(r);
1689
1690 r = strv_split_colon_pairs(&l, p);
1691 if (r < 0)
1692 return log_error_errno(r, "Failed to parse argument: %m");
1693
1694 STRV_FOREACH_PAIR(first, second, l) {
1695 r = sd_bus_message_append(m, "(ss)",
1696 !isempty(*second) ? *first : "root",
1697 !isempty(*second) ? *second : *first);
1698 if (r < 0)
1699 return bus_log_create_error(r);
1700 }
1701
1702 r = sd_bus_message_close_container(m);
1703 if (r < 0)
1704 return bus_log_create_error(r);
1705
1706 r = sd_bus_message_close_container(m);
1707 if (r < 0)
1708 return bus_log_create_error(r);
1709
1710 r = sd_bus_message_close_container(m);
1711 if (r < 0)
1712 return bus_log_create_error(r);
1713
1714 return 1;
1715 }
1716
1717 if (streq(field, "MountImages")) {
1718 const char *p = eq;
1719
1720 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1721 if (r < 0)
1722 return bus_log_create_error(r);
1723
1724 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1725 if (r < 0)
1726 return bus_log_create_error(r);
1727
1728 r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
1729 if (r < 0)
1730 return bus_log_create_error(r);
1731
1732 r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
1733 if (r < 0)
1734 return bus_log_create_error(r);
1735
1736 for (;;) {
1737 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
1738 const char *q = NULL, *source = NULL;
1739 bool permissive = false;
1740
1741 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1742 if (r < 0)
1743 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1744 if (r == 0)
1745 break;
1746
1747 q = tuple;
1748 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
1749 if (r < 0)
1750 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1751 if (r == 0)
1752 continue;
1753
1754 source = first;
1755 if (source[0] == '-') {
1756 permissive = true;
1757 source++;
1758 }
1759
1760 if (isempty(second))
1761 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1762 "Missing argument after ':': %s",
1763 eq);
1764
1765 r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
1766 if (r < 0)
1767 return bus_log_create_error(r);
1768
1769 r = sd_bus_message_append(m, "ssb", source, second, permissive);
1770 if (r < 0)
1771 return bus_log_create_error(r);
1772
1773 r = sd_bus_message_open_container(m, 'a', "(ss)");
1774 if (r < 0)
1775 return bus_log_create_error(r);
1776
1777 for (;;) {
1778 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1779
1780 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1781 if (r < 0)
1782 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1783 if (r == 0)
1784 break;
1785 /* Single set of options, applying to the root partition/single filesystem */
1786 if (r == 1) {
1787 r = sd_bus_message_append(m, "(ss)", "root", partition);
1788 if (r < 0)
1789 return bus_log_create_error(r);
1790
1791 break;
1792 }
1793
1794 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1795 if (r < 0)
1796 return bus_log_create_error(r);
1797 }
1798
1799 r = sd_bus_message_close_container(m);
1800 if (r < 0)
1801 return bus_log_create_error(r);
1802
1803 r = sd_bus_message_close_container(m);
1804 if (r < 0)
1805 return bus_log_create_error(r);
1806 }
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 r = sd_bus_message_close_container(m);
1817 if (r < 0)
1818 return bus_log_create_error(r);
1819
1820 return 1;
1821 }
1822
1823 if (streq(field, "ExtensionImages")) {
1824 const char *p = eq;
1825
1826 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1827 if (r < 0)
1828 return bus_log_create_error(r);
1829
1830 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1831 if (r < 0)
1832 return bus_log_create_error(r);
1833
1834 r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
1835 if (r < 0)
1836 return bus_log_create_error(r);
1837
1838 r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
1839 if (r < 0)
1840 return bus_log_create_error(r);
1841
1842 for (;;) {
1843 _cleanup_free_ char *source = NULL, *tuple = NULL;
1844 const char *q = NULL, *s = NULL;
1845 bool permissive = false;
1846
1847 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1848 if (r < 0)
1849 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
1850 if (r == 0)
1851 break;
1852
1853 q = tuple;
1854 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
1855 if (r < 0)
1856 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
1857 if (r == 0)
1858 continue;
1859
1860 s = source;
1861 if (s[0] == '-') {
1862 permissive = true;
1863 s++;
1864 }
1865
1866 r = sd_bus_message_open_container(m, 'r', "sba(ss)");
1867 if (r < 0)
1868 return bus_log_create_error(r);
1869
1870 r = sd_bus_message_append(m, "sb", s, permissive);
1871 if (r < 0)
1872 return bus_log_create_error(r);
1873
1874 r = sd_bus_message_open_container(m, 'a', "(ss)");
1875 if (r < 0)
1876 return bus_log_create_error(r);
1877
1878 for (;;) {
1879 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1880
1881 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1882 if (r < 0)
1883 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
1884 if (r == 0)
1885 break;
1886 /* Single set of options, applying to the root partition/single filesystem */
1887 if (r == 1) {
1888 r = sd_bus_message_append(m, "(ss)", "root", partition);
1889 if (r < 0)
1890 return bus_log_create_error(r);
1891
1892 break;
1893 }
1894
1895 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1896 if (r < 0)
1897 return bus_log_create_error(r);
1898 }
1899
1900 r = sd_bus_message_close_container(m);
1901 if (r < 0)
1902 return bus_log_create_error(r);
1903
1904 r = sd_bus_message_close_container(m);
1905 if (r < 0)
1906 return bus_log_create_error(r);
1907 }
1908
1909 r = sd_bus_message_close_container(m);
1910 if (r < 0)
1911 return bus_log_create_error(r);
1912
1913 r = sd_bus_message_close_container(m);
1914 if (r < 0)
1915 return bus_log_create_error(r);
1916
1917 r = sd_bus_message_close_container(m);
1918 if (r < 0)
1919 return bus_log_create_error(r);
1920
1921 return 1;
1922 }
1923
1924 return 0;
1925 }
1926
1927 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
1928 if (streq(field, "KillMode"))
1929 return bus_append_string(m, field, eq);
1930
1931 if (STR_IN_SET(field, "SendSIGHUP",
1932 "SendSIGKILL"))
1933 return bus_append_parse_boolean(m, field, eq);
1934
1935 if (STR_IN_SET(field, "KillSignal",
1936 "RestartKillSignal",
1937 "FinalKillSignal",
1938 "WatchdogSignal"))
1939 return bus_append_signal_from_string(m, field, eq);
1940
1941 return 0;
1942 }
1943
1944 static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
1945
1946 if (STR_IN_SET(field, "What",
1947 "Where",
1948 "Options",
1949 "Type"))
1950 return bus_append_string(m, field, eq);
1951
1952 if (streq(field, "TimeoutSec"))
1953 return bus_append_parse_sec_rename(m, field, eq);
1954
1955 if (streq(field, "DirectoryMode"))
1956 return bus_append_parse_mode(m, field, eq);
1957
1958 if (STR_IN_SET(field, "SloppyOptions",
1959 "LazyUnmount",
1960 "ForceUnmount",
1961 "ReadwriteOnly"))
1962 return bus_append_parse_boolean(m, field, eq);
1963
1964 return 0;
1965 }
1966
1967 static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1968 int r;
1969
1970 if (streq(field, "MakeDirectory"))
1971 return bus_append_parse_boolean(m, field, eq);
1972
1973 if (streq(field, "DirectoryMode"))
1974 return bus_append_parse_mode(m, field, eq);
1975
1976 if (STR_IN_SET(field, "PathExists",
1977 "PathExistsGlob",
1978 "PathChanged",
1979 "PathModified",
1980 "DirectoryNotEmpty")) {
1981 if (isempty(eq))
1982 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1983 else
1984 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1985 if (r < 0)
1986 return bus_log_create_error(r);
1987
1988 return 1;
1989 }
1990
1991 return 0;
1992 }
1993
1994 static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
1995 if (streq(field, "RuntimeMaxSec"))
1996 return bus_append_parse_sec_rename(m, field, eq);
1997
1998 if (streq(field, "TimeoutStopSec"))
1999 return bus_append_parse_sec_rename(m, field, eq);
2000
2001 return 0;
2002 }
2003
2004 static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
2005 int r;
2006
2007 if (STR_IN_SET(field, "PIDFile",
2008 "Type",
2009 "Restart",
2010 "BusName",
2011 "NotifyAccess",
2012 "USBFunctionDescriptors",
2013 "USBFunctionStrings",
2014 "OOMPolicy",
2015 "TimeoutStartFailureMode",
2016 "TimeoutStopFailureMode"))
2017 return bus_append_string(m, field, eq);
2018
2019 if (STR_IN_SET(field, "PermissionsStartOnly",
2020 "RootDirectoryStartOnly",
2021 "RemainAfterExit",
2022 "GuessMainPID"))
2023 return bus_append_parse_boolean(m, field, eq);
2024
2025 if (STR_IN_SET(field, "RestartSec",
2026 "TimeoutStartSec",
2027 "TimeoutStopSec",
2028 "TimeoutAbortSec",
2029 "RuntimeMaxSec",
2030 "WatchdogSec"))
2031 return bus_append_parse_sec_rename(m, field, eq);
2032
2033 if (streq(field, "TimeoutSec")) {
2034 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2035 if (r < 0)
2036 return r;
2037
2038 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2039 }
2040
2041 if (streq(field, "FileDescriptorStoreMax"))
2042 return bus_append_safe_atou(m, field, eq);
2043
2044 if (STR_IN_SET(field, "ExecCondition",
2045 "ExecStartPre",
2046 "ExecStart",
2047 "ExecStartPost",
2048 "ExecConditionEx",
2049 "ExecStartPreEx",
2050 "ExecStartEx",
2051 "ExecStartPostEx",
2052 "ExecReload",
2053 "ExecStop",
2054 "ExecStopPost",
2055 "ExecReloadEx",
2056 "ExecStopEx",
2057 "ExecStopPostEx"))
2058 return bus_append_exec_command(m, field, eq);
2059
2060 if (STR_IN_SET(field, "RestartPreventExitStatus",
2061 "RestartForceExitStatus",
2062 "SuccessExitStatus")) {
2063 _cleanup_free_ int *status = NULL, *signal = NULL;
2064 size_t n_status = 0, n_signal = 0;
2065 const char *p;
2066
2067 for (p = eq;;) {
2068 _cleanup_free_ char *word = NULL;
2069
2070 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2071 if (r == 0)
2072 break;
2073 if (r == -ENOMEM)
2074 return log_oom();
2075 if (r < 0)
2076 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2077
2078 /* We need to call exit_status_from_string() first, because we want
2079 * to parse numbers as exit statuses, not signals. */
2080
2081 r = exit_status_from_string(word);
2082 if (r >= 0) {
2083 assert(r >= 0 && r < 256);
2084
2085 status = reallocarray(status, n_status + 1, sizeof(int));
2086 if (!status)
2087 return log_oom();
2088
2089 status[n_status++] = r;
2090
2091 } else if ((r = signal_from_string(word)) >= 0) {
2092 signal = reallocarray(signal, n_signal + 1, sizeof(int));
2093 if (!signal)
2094 return log_oom();
2095
2096 signal[n_signal++] = r;
2097
2098 } else
2099 /* original r from exit_status_to_string() */
2100 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2101 word, field);
2102 }
2103
2104 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2105 if (r < 0)
2106 return bus_log_create_error(r);
2107
2108 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2109 if (r < 0)
2110 return bus_log_create_error(r);
2111
2112 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2113 if (r < 0)
2114 return bus_log_create_error(r);
2115
2116 r = sd_bus_message_open_container(m, 'r', "aiai");
2117 if (r < 0)
2118 return bus_log_create_error(r);
2119
2120 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
2121 if (r < 0)
2122 return bus_log_create_error(r);
2123
2124 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
2125 if (r < 0)
2126 return bus_log_create_error(r);
2127
2128 r = sd_bus_message_close_container(m);
2129 if (r < 0)
2130 return bus_log_create_error(r);
2131
2132 r = sd_bus_message_close_container(m);
2133 if (r < 0)
2134 return bus_log_create_error(r);
2135
2136 r = sd_bus_message_close_container(m);
2137 if (r < 0)
2138 return bus_log_create_error(r);
2139
2140 return 1;
2141 }
2142
2143 return 0;
2144 }
2145
2146 static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2147 int r;
2148
2149 if (STR_IN_SET(field, "Accept",
2150 "FlushPending",
2151 "Writable",
2152 "KeepAlive",
2153 "NoDelay",
2154 "FreeBind",
2155 "Transparent",
2156 "Broadcast",
2157 "PassCredentials",
2158 "PassSecurity",
2159 "PassPacketInfo",
2160 "ReusePort",
2161 "RemoveOnStop",
2162 "SELinuxContextFromNet"))
2163 return bus_append_parse_boolean(m, field, eq);
2164
2165 if (STR_IN_SET(field, "Priority",
2166 "IPTTL",
2167 "Mark"))
2168 return bus_append_safe_atoi(m, field, eq);
2169
2170 if (streq(field, "IPTOS"))
2171 return bus_append_ip_tos_from_string(m, field, eq);
2172
2173 if (STR_IN_SET(field, "Backlog",
2174 "MaxConnections",
2175 "MaxConnectionsPerSource",
2176 "KeepAliveProbes",
2177 "TriggerLimitBurst"))
2178 return bus_append_safe_atou(m, field, eq);
2179
2180 if (STR_IN_SET(field, "SocketMode",
2181 "DirectoryMode"))
2182 return bus_append_parse_mode(m, field, eq);
2183
2184 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2185 "MessageQueueMessageSize"))
2186 return bus_append_safe_atoi64(m, field, eq);
2187
2188 if (STR_IN_SET(field, "TimeoutSec",
2189 "KeepAliveTimeSec",
2190 "KeepAliveIntervalSec",
2191 "DeferAcceptSec",
2192 "TriggerLimitIntervalSec"))
2193 return bus_append_parse_sec_rename(m, field, eq);
2194
2195 if (STR_IN_SET(field, "ReceiveBuffer",
2196 "SendBuffer",
2197 "PipeSize"))
2198 return bus_append_parse_size(m, field, eq, 1024);
2199
2200 if (STR_IN_SET(field, "ExecStartPre",
2201 "ExecStartPost",
2202 "ExecReload",
2203 "ExecStopPost"))
2204 return bus_append_exec_command(m, field, eq);
2205
2206 if (STR_IN_SET(field, "SmackLabel",
2207 "SmackLabelIPIn",
2208 "SmackLabelIPOut",
2209 "TCPCongestion",
2210 "BindToDevice",
2211 "BindIPv6Only",
2212 "FileDescriptorName",
2213 "SocketUser",
2214 "SocketGroup",
2215 "Timestamping"))
2216 return bus_append_string(m, field, eq);
2217
2218 if (streq(field, "Symlinks"))
2219 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
2220
2221 if (streq(field, "SocketProtocol"))
2222 return bus_append_parse_ip_protocol(m, field, eq);
2223
2224 if (STR_IN_SET(field, "ListenStream",
2225 "ListenDatagram",
2226 "ListenSequentialPacket",
2227 "ListenNetlink",
2228 "ListenSpecial",
2229 "ListenMessageQueue",
2230 "ListenFIFO",
2231 "ListenUSBFunction")) {
2232 if (isempty(eq))
2233 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2234 else
2235 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
2236 if (r < 0)
2237 return bus_log_create_error(r);
2238
2239 return 1;
2240 }
2241
2242 return 0;
2243 }
2244 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
2245 int r;
2246
2247 if (STR_IN_SET(field, "WakeSystem",
2248 "RemainAfterElapse",
2249 "Persistent",
2250 "OnTimezoneChange",
2251 "OnClockChange",
2252 "FixedRandomDelay"))
2253 return bus_append_parse_boolean(m, field, eq);
2254
2255 if (STR_IN_SET(field, "AccuracySec",
2256 "RandomizedDelaySec"))
2257 return bus_append_parse_sec_rename(m, field, eq);
2258
2259 if (STR_IN_SET(field, "OnActiveSec",
2260 "OnBootSec",
2261 "OnStartupSec",
2262 "OnUnitActiveSec",
2263 "OnUnitInactiveSec")) {
2264 if (isempty(eq))
2265 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2266 else {
2267 usec_t t;
2268 r = parse_sec(eq, &t);
2269 if (r < 0)
2270 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
2271
2272 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2273 }
2274 if (r < 0)
2275 return bus_log_create_error(r);
2276
2277 return 1;
2278 }
2279
2280 if (streq(field, "OnCalendar")) {
2281 if (isempty(eq))
2282 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2283 else
2284 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2285 if (r < 0)
2286 return bus_log_create_error(r);
2287
2288 return 1;
2289 }
2290
2291 return 0;
2292 }
2293
2294 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
2295 ConditionType t = _CONDITION_TYPE_INVALID;
2296 bool is_condition = false;
2297 int r;
2298
2299 if (STR_IN_SET(field, "Description",
2300 "SourcePath",
2301 "OnFailureJobMode",
2302 "JobTimeoutAction",
2303 "JobTimeoutRebootArgument",
2304 "StartLimitAction",
2305 "FailureAction",
2306 "SuccessAction",
2307 "RebootArgument",
2308 "CollectMode"))
2309 return bus_append_string(m, field, eq);
2310
2311 if (STR_IN_SET(field, "StopWhenUnneeded",
2312 "RefuseManualStart",
2313 "RefuseManualStop",
2314 "AllowIsolate",
2315 "IgnoreOnIsolate",
2316 "DefaultDependencies"))
2317 return bus_append_parse_boolean(m, field, eq);
2318
2319 if (STR_IN_SET(field, "JobTimeoutSec",
2320 "JobRunningTimeoutSec",
2321 "StartLimitIntervalSec"))
2322 return bus_append_parse_sec_rename(m, field, eq);
2323
2324 if (streq(field, "StartLimitBurst"))
2325 return bus_append_safe_atou(m, field, eq);
2326
2327 if (STR_IN_SET(field, "SuccessActionExitStatus",
2328 "FailureActionExitStatus")) {
2329 if (isempty(eq))
2330 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2331 else {
2332 uint8_t u;
2333
2334 r = safe_atou8(eq, &u);
2335 if (r < 0)
2336 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2337
2338 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2339 }
2340 if (r < 0)
2341 return bus_log_create_error(r);
2342
2343 return 1;
2344 }
2345
2346 if (unit_dependency_from_string(field) >= 0 ||
2347 STR_IN_SET(field, "Documentation",
2348 "RequiresMountsFor",
2349 "Markers"))
2350 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
2351
2352 t = condition_type_from_string(field);
2353 if (t >= 0)
2354 is_condition = true;
2355 else
2356 t = assert_type_from_string(field);
2357 if (t >= 0) {
2358 if (isempty(eq))
2359 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2360 else {
2361 const char *p = eq;
2362 int trigger, negate;
2363
2364 trigger = *p == '|';
2365 if (trigger)
2366 p++;
2367
2368 negate = *p == '!';
2369 if (negate)
2370 p++;
2371
2372 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2373 field, trigger, negate, p);
2374 }
2375 if (r < 0)
2376 return bus_log_create_error(r);
2377
2378 return 1;
2379 }
2380
2381 return 0;
2382 }
2383
2384 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2385 const char *eq, *field;
2386 int r;
2387
2388 assert(m);
2389 assert(assignment);
2390
2391 eq = strchr(assignment, '=');
2392 if (!eq)
2393 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2394 "Not an assignment: %s", assignment);
2395
2396 field = strndupa(assignment, eq - assignment);
2397 eq++;
2398
2399 switch (t) {
2400 case UNIT_SERVICE:
2401 r = bus_append_cgroup_property(m, field, eq);
2402 if (r != 0)
2403 return r;
2404
2405 r = bus_append_execute_property(m, field, eq);
2406 if (r != 0)
2407 return r;
2408
2409 r = bus_append_kill_property(m, field, eq);
2410 if (r != 0)
2411 return r;
2412
2413 r = bus_append_service_property(m, field, eq);
2414 if (r != 0)
2415 return r;
2416 break;
2417
2418 case UNIT_SOCKET:
2419 r = bus_append_cgroup_property(m, field, eq);
2420 if (r != 0)
2421 return r;
2422
2423 r = bus_append_execute_property(m, field, eq);
2424 if (r != 0)
2425 return r;
2426
2427 r = bus_append_kill_property(m, field, eq);
2428 if (r != 0)
2429 return r;
2430
2431 r = bus_append_socket_property(m, field, eq);
2432 if (r != 0)
2433 return r;
2434 break;
2435
2436 case UNIT_TIMER:
2437 r = bus_append_timer_property(m, field, eq);
2438 if (r != 0)
2439 return r;
2440 break;
2441
2442 case UNIT_PATH:
2443 r = bus_append_path_property(m, field, eq);
2444 if (r != 0)
2445 return r;
2446 break;
2447
2448 case UNIT_SLICE:
2449 r = bus_append_cgroup_property(m, field, eq);
2450 if (r != 0)
2451 return r;
2452 break;
2453
2454 case UNIT_SCOPE:
2455 r = bus_append_cgroup_property(m, field, eq);
2456 if (r != 0)
2457 return r;
2458
2459 r = bus_append_kill_property(m, field, eq);
2460 if (r != 0)
2461 return r;
2462
2463 r = bus_append_scope_property(m, field, eq);
2464 if (r != 0)
2465 return r;
2466 break;
2467
2468 case UNIT_MOUNT:
2469 r = bus_append_cgroup_property(m, field, eq);
2470 if (r != 0)
2471 return r;
2472
2473 r = bus_append_execute_property(m, field, eq);
2474 if (r != 0)
2475 return r;
2476
2477 r = bus_append_kill_property(m, field, eq);
2478 if (r != 0)
2479 return r;
2480
2481 r = bus_append_mount_property(m, field, eq);
2482 if (r != 0)
2483 return r;
2484
2485 break;
2486
2487 case UNIT_AUTOMOUNT:
2488 r = bus_append_automount_property(m, field, eq);
2489 if (r != 0)
2490 return r;
2491
2492 break;
2493
2494 case UNIT_TARGET:
2495 case UNIT_DEVICE:
2496 case UNIT_SWAP:
2497 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2498 "Not supported unit type");
2499
2500 default:
2501 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2502 "Invalid unit type");
2503 }
2504
2505 r = bus_append_unit_property(m, field, eq);
2506 if (r != 0)
2507 return r;
2508
2509 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2510 "Unknown assignment: %s", assignment);
2511 }
2512
2513 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
2514 char **i;
2515 int r;
2516
2517 assert(m);
2518
2519 STRV_FOREACH(i, l) {
2520 r = bus_append_unit_property_assignment(m, t, *i);
2521 if (r < 0)
2522 return r;
2523 }
2524
2525 return 0;
2526 }
2527
2528 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
2529 const char *type, *path, *source;
2530 int r;
2531
2532 /* changes is dereferenced when calling unit_file_dump_changes() later,
2533 * so we have to make sure this is not NULL. */
2534 assert(changes);
2535 assert(n_changes);
2536
2537 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2538 if (r < 0)
2539 return bus_log_parse_error(r);
2540
2541 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2542 /* We expect only "success" changes to be sent over the bus.
2543 Hence, reject anything negative. */
2544 int ch = unit_file_change_type_from_string(type);
2545 if (ch < 0) {
2546 log_notice_errno(ch, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2547 type, path);
2548 continue;
2549 }
2550
2551 r = unit_file_changes_add(changes, n_changes, ch, path, source);
2552 if (r < 0)
2553 return r;
2554 }
2555 if (r < 0)
2556 return bus_log_parse_error(r);
2557
2558 r = sd_bus_message_exit_container(m);
2559 if (r < 0)
2560 return bus_log_parse_error(r);
2561
2562 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
2563 return 0;
2564 }
2565
2566 int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2567 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2568 _cleanup_free_ char *path = NULL;
2569 int r;
2570
2571 path = unit_dbus_path_from_name(name);
2572 if (!path)
2573 return log_oom();
2574
2575 /* This function warns on it's own, because otherwise it'd be awkward to pass
2576 * the dbus error message around. */
2577
2578 r = sd_bus_get_property_string(
2579 bus,
2580 "org.freedesktop.systemd1",
2581 path,
2582 "org.freedesktop.systemd1.Unit",
2583 "LoadState",
2584 &error,
2585 load_state);
2586 if (r < 0)
2587 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2588
2589 return 0;
2590 }
2591
2592 int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2593 int r;
2594
2595 /* First, order by machine */
2596 r = strcasecmp_ptr(a->machine, b->machine);
2597 if (r != 0)
2598 return r;
2599
2600 /* Second, order by unit type */
2601 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2602 if (r != 0)
2603 return r;
2604
2605 /* Third, order by name */
2606 return strcasecmp(a->id, b->id);
2607 }