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