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