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