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