]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
Merge pull request #31899 from yuwata/sd-journal-add-match
[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);
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 "MemoryZSwapWriteback",
566 "IOAccounting",
567 "BlockIOAccounting",
568 "TasksAccounting",
569 "IPAccounting",
570 "CoredumpReceive"))
571 return bus_append_parse_boolean(m, field, eq);
572
573 if (STR_IN_SET(field, "CPUWeight",
574 "StartupCPUWeight"))
575 return bus_append_cg_cpu_weight_parse(m, field, eq);
576
577 if (STR_IN_SET(field, "IOWeight",
578 "StartupIOWeight"))
579 return bus_append_cg_weight_parse(m, field, eq);
580
581 if (STR_IN_SET(field, "CPUShares",
582 "StartupCPUShares"))
583 return bus_append_cg_cpu_shares_parse(m, field, eq);
584
585 if (STR_IN_SET(field, "AllowedCPUs",
586 "StartupAllowedCPUs",
587 "AllowedMemoryNodes",
588 "StartupAllowedMemoryNodes")) {
589 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
590 _cleanup_free_ uint8_t *array = NULL;
591 size_t allocated;
592
593 r = parse_cpu_set(eq, &cpuset);
594 if (r < 0)
595 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
596
597 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
598 if (r < 0)
599 return log_error_errno(r, "Failed to serialize CPUSet: %m");
600
601 return bus_append_byte_array(m, field, array, allocated);
602 }
603
604 if (STR_IN_SET(field, "BlockIOWeight",
605 "StartupBlockIOWeight"))
606 return bus_append_cg_blkio_weight_parse(m, field, eq);
607
608 if (streq(field, "DisableControllers"))
609 return bus_append_strv(m, "DisableControllers", eq, EXTRACT_UNQUOTE);
610
611 if (streq(field, "Delegate")) {
612 r = parse_boolean(eq);
613 if (r < 0)
614 return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_UNQUOTE);
615
616 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
617 if (r < 0)
618 return bus_log_create_error(r);
619
620 return 1;
621 }
622
623 if (STR_IN_SET(field, "MemoryMin",
624 "DefaultMemoryLow",
625 "DefaultMemoryMin",
626 "MemoryLow",
627 "MemoryHigh",
628 "MemoryMax",
629 "MemorySwapMax",
630 "MemoryZSwapMax",
631 "MemoryLimit",
632 "TasksMax")) {
633
634 if (streq(eq, "infinity")) {
635 r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
636 if (r < 0)
637 return bus_log_create_error(r);
638 return 1;
639 } else if (isempty(eq)) {
640 uint64_t empty_value = STR_IN_SET(field,
641 "DefaultMemoryLow",
642 "DefaultMemoryMin",
643 "MemoryLow",
644 "MemoryMin") ?
645 CGROUP_LIMIT_MIN :
646 CGROUP_LIMIT_MAX;
647
648 r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
649 if (r < 0)
650 return bus_log_create_error(r);
651 return 1;
652 }
653
654 r = parse_permyriad(eq);
655 if (r >= 0) {
656 char *n;
657
658 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
659 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
660 * size can be determined server-side. */
661
662 n = strjoina(field, "Scale");
663 r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
664 if (r < 0)
665 return bus_log_create_error(r);
666
667 return 1;
668 }
669
670 if (streq(field, "TasksMax"))
671 return bus_append_safe_atou64(m, field, eq);
672
673 return bus_append_parse_size(m, field, eq, 1024);
674 }
675
676 if (streq(field, "CPUQuota")) {
677 if (isempty(eq))
678 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
679 else {
680 r = parse_permyriad_unbounded(eq);
681 if (r == 0)
682 return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
683 "CPU quota too small.");
684 if (r < 0)
685 return log_error_errno(r, "CPU quota '%s' invalid.", eq);
686
687 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
688 }
689
690 if (r < 0)
691 return bus_log_create_error(r);
692
693 return 1;
694 }
695
696 if (streq(field, "CPUQuotaPeriodSec")) {
697 usec_t u = USEC_INFINITY;
698
699 r = parse_sec_def_infinity(eq, &u);
700 if (r < 0)
701 return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
702
703 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
704 if (r < 0)
705 return bus_log_create_error(r);
706
707 return 1;
708 }
709
710 if (streq(field, "DeviceAllow")) {
711 if (isempty(eq))
712 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
713 else {
714 const char *path = eq, *rwm = NULL, *e;
715
716 e = strchr(eq, ' ');
717 if (e) {
718 path = strndupa_safe(eq, e - eq);
719 rwm = e+1;
720 }
721
722 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
723 }
724
725 if (r < 0)
726 return bus_log_create_error(r);
727
728 return 1;
729 }
730
731 if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
732 if (isempty(eq))
733 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
734 else {
735 const char *path, *bandwidth, *e;
736 uint64_t bytes;
737
738 e = strchr(eq, ' ');
739 if (!e)
740 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
741 "Failed to parse %s value %s.",
742 field, eq);
743
744 path = strndupa_safe(eq, e - eq);
745 bandwidth = e+1;
746
747 if (streq(bandwidth, "infinity"))
748 bytes = CGROUP_LIMIT_MAX;
749 else {
750 r = parse_size(bandwidth, 1000, &bytes);
751 if (r < 0)
752 return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
753 }
754
755 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
756 }
757
758 if (r < 0)
759 return bus_log_create_error(r);
760
761 return 1;
762 }
763
764 if (STR_IN_SET(field, "IODeviceWeight",
765 "BlockIODeviceWeight")) {
766 if (isempty(eq))
767 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
768 else {
769 const char *path, *weight, *e;
770 uint64_t u;
771
772 e = strchr(eq, ' ');
773 if (!e)
774 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
775 "Failed to parse %s value %s.",
776 field, eq);
777
778 path = strndupa_safe(eq, e - eq);
779 weight = e+1;
780
781 r = safe_atou64(weight, &u);
782 if (r < 0)
783 return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
784
785 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
786 }
787
788 if (r < 0)
789 return bus_log_create_error(r);
790
791 return 1;
792 }
793
794 if (streq(field, "IODeviceLatencyTargetSec")) {
795 const char *field_usec = "IODeviceLatencyTargetUSec";
796
797 if (isempty(eq))
798 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
799 else {
800 const char *path, *target, *e;
801 usec_t usec;
802
803 e = strchr(eq, ' ');
804 if (!e)
805 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
806 "Failed to parse %s value %s.",
807 field, eq);
808
809 path = strndupa_safe(eq, e - eq);
810 target = e+1;
811
812 r = parse_sec(target, &usec);
813 if (r < 0)
814 return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
815
816 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
817 }
818
819 if (r < 0)
820 return bus_log_create_error(r);
821
822 return 1;
823 }
824
825 if (STR_IN_SET(field, "IPAddressAllow",
826 "IPAddressDeny")) {
827 unsigned char prefixlen;
828 union in_addr_union prefix = {};
829 int family;
830
831 if (isempty(eq)) {
832 r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
833 if (r < 0)
834 return bus_log_create_error(r);
835
836 return 1;
837 }
838
839 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
840 if (r < 0)
841 return bus_log_create_error(r);
842
843 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
844 if (r < 0)
845 return bus_log_create_error(r);
846
847 r = sd_bus_message_open_container(m, 'v', "a(iayu)");
848 if (r < 0)
849 return bus_log_create_error(r);
850
851 r = sd_bus_message_open_container(m, 'a', "(iayu)");
852 if (r < 0)
853 return bus_log_create_error(r);
854
855 if (streq(eq, "any")) {
856 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
857
858 r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
859 if (r < 0)
860 return bus_log_create_error(r);
861
862 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
863 if (r < 0)
864 return bus_log_create_error(r);
865
866 } else if (is_localhost(eq)) {
867 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
868
869 prefix.in.s_addr = htobe32(0x7f000000);
870 r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
871 if (r < 0)
872 return bus_log_create_error(r);
873
874 prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
875 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
876 if (r < 0)
877 return r;
878
879 } else if (streq(eq, "link-local")) {
880 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
881
882 prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
883 r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
884 if (r < 0)
885 return bus_log_create_error(r);
886
887 prefix.in6 = (struct in6_addr) {
888 .s6_addr32[0] = htobe32(0xfe800000)
889 };
890 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
891 if (r < 0)
892 return bus_log_create_error(r);
893
894 } else if (streq(eq, "multicast")) {
895 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
896
897 prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
898 r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
899 if (r < 0)
900 return bus_log_create_error(r);
901
902 prefix.in6 = (struct in6_addr) {
903 .s6_addr32[0] = htobe32(0xff000000)
904 };
905 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
906 if (r < 0)
907 return bus_log_create_error(r);
908
909 } else {
910 for (;;) {
911 _cleanup_free_ char *word = NULL;
912
913 r = extract_first_word(&eq, &word, NULL, 0);
914 if (r == 0)
915 break;
916 if (r == -ENOMEM)
917 return log_oom();
918 if (r < 0)
919 return log_error_errno(r, "Failed to parse %s: %s", field, eq);
920
921 r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
922 if (r < 0)
923 return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
924
925 r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
926 if (r < 0)
927 return bus_log_create_error(r);
928 }
929 }
930
931 r = sd_bus_message_close_container(m);
932 if (r < 0)
933 return bus_log_create_error(r);
934
935 r = sd_bus_message_close_container(m);
936 if (r < 0)
937 return bus_log_create_error(r);
938
939 r = sd_bus_message_close_container(m);
940 if (r < 0)
941 return bus_log_create_error(r);
942
943 return 1;
944 }
945
946 if (STR_IN_SET(field, "IPIngressFilterPath",
947 "IPEgressFilterPath")) {
948 if (isempty(eq))
949 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
950 else
951 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
952
953 if (r < 0)
954 return bus_log_create_error(r);
955
956 return 1;
957 }
958
959 if (streq(field, "BPFProgram")) {
960 if (isempty(eq))
961 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
962 else {
963 _cleanup_free_ char *word = NULL;
964
965 r = extract_first_word(&eq, &word, ":", 0);
966 if (r == -ENOMEM)
967 return log_oom();
968 if (r < 0)
969 return log_error_errno(r, "Failed to parse %s: %m", field);
970
971 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
972 }
973 if (r < 0)
974 return bus_log_create_error(r);
975
976 return 1;
977 }
978
979 if (STR_IN_SET(field, "SocketBindAllow",
980 "SocketBindDeny")) {
981 if (isempty(eq))
982 r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
983 else {
984 int32_t family, ip_protocol;
985 uint16_t nr_ports, port_min;
986
987 r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
988 if (r == -ENOMEM)
989 return log_oom();
990 if (r < 0)
991 return log_error_errno(r, "Failed to parse %s", field);
992
993 r = sd_bus_message_append(
994 m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
995 }
996 if (r < 0)
997 return bus_log_create_error(r);
998
999 return 1;
1000 }
1001
1002 if (streq(field, "MemoryPressureThresholdSec"))
1003 return bus_append_parse_sec_rename(m, field, eq);
1004
1005 if (streq(field, "NFTSet"))
1006 return bus_append_nft_set(m, field, eq);
1007
1008 return 0;
1009 }
1010
1011 static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
1012 if (STR_IN_SET(field, "Where",
1013 "ExtraOptions"))
1014 return bus_append_string(m, field, eq);
1015
1016 if (streq(field, "DirectoryMode"))
1017 return bus_append_parse_mode(m, field, eq);
1018
1019 if (streq(field, "TimeoutIdleSec"))
1020 return bus_append_parse_sec_rename(m, field, eq);
1021
1022 return 0;
1023 }
1024
1025 static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
1026 const char *suffix;
1027 int r;
1028
1029 if (STR_IN_SET(field, "User",
1030 "Group",
1031 "UtmpIdentifier",
1032 "UtmpMode",
1033 "PAMName",
1034 "TTYPath",
1035 "WorkingDirectory",
1036 "RootDirectory",
1037 "SyslogIdentifier",
1038 "ProtectSystem",
1039 "ProtectHome",
1040 "SELinuxContext",
1041 "RootImage",
1042 "RootVerity",
1043 "RuntimeDirectoryPreserve",
1044 "Personality",
1045 "KeyringMode",
1046 "ProtectProc",
1047 "ProcSubset",
1048 "NetworkNamespacePath",
1049 "IPCNamespacePath",
1050 "LogNamespace",
1051 "RootImagePolicy",
1052 "MountImagePolicy",
1053 "ExtensionImagePolicy"))
1054 return bus_append_string(m, field, eq);
1055
1056 if (STR_IN_SET(field, "IgnoreSIGPIPE",
1057 "TTYVHangup",
1058 "TTYReset",
1059 "TTYVTDisallocate",
1060 "PrivateTmp",
1061 "PrivateDevices",
1062 "PrivateNetwork",
1063 "PrivateUsers",
1064 "PrivateMounts",
1065 "PrivateIPC",
1066 "NoNewPrivileges",
1067 "SyslogLevelPrefix",
1068 "MemoryDenyWriteExecute",
1069 "RestrictRealtime",
1070 "DynamicUser",
1071 "RemoveIPC",
1072 "ProtectKernelTunables",
1073 "ProtectKernelModules",
1074 "ProtectKernelLogs",
1075 "ProtectClock",
1076 "ProtectControlGroups",
1077 "MountAPIVFS",
1078 "CPUSchedulingResetOnFork",
1079 "LockPersonality",
1080 "ProtectHostname",
1081 "MemoryKSM",
1082 "RestrictSUIDSGID",
1083 "RootEphemeral",
1084 "SetLoginEnvironment"))
1085 return bus_append_parse_boolean(m, field, eq);
1086
1087 if (STR_IN_SET(field, "ReadWriteDirectories",
1088 "ReadOnlyDirectories",
1089 "InaccessibleDirectories",
1090 "ReadWritePaths",
1091 "ReadOnlyPaths",
1092 "InaccessiblePaths",
1093 "ExecPaths",
1094 "NoExecPaths",
1095 "ExecSearchPath",
1096 "ExtensionDirectories",
1097 "ConfigurationDirectory",
1098 "SupplementaryGroups",
1099 "SystemCallArchitectures"))
1100 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
1101
1102 if (STR_IN_SET(field, "SyslogLevel",
1103 "LogLevelMax"))
1104 return bus_append_log_level_from_string(m, field, eq);
1105
1106 if (streq(field, "SyslogFacility"))
1107 return bus_append_log_facility_unshifted_from_string(m, field, eq);
1108
1109 if (streq(field, "SecureBits"))
1110 return bus_append_secure_bits_from_string(m, field, eq);
1111
1112 if (streq(field, "CPUSchedulingPolicy"))
1113 return bus_append_sched_policy_from_string(m, field, eq);
1114
1115 if (STR_IN_SET(field, "CPUSchedulingPriority",
1116 "OOMScoreAdjust"))
1117 return bus_append_safe_atoi(m, field, eq);
1118
1119 if (streq(field, "CoredumpFilter"))
1120 return bus_append_coredump_filter_mask_from_string(m, field, eq);
1121
1122 if (streq(field, "Nice"))
1123 return bus_append_parse_nice(m, field, eq);
1124
1125 if (streq(field, "SystemCallErrorNumber"))
1126 return bus_append_seccomp_parse_errno_or_action(m, field, eq);
1127
1128 if (streq(field, "IOSchedulingClass"))
1129 return bus_append_ioprio_class_from_string(m, field, eq);
1130
1131 if (streq(field, "IOSchedulingPriority"))
1132 return bus_append_ioprio_parse_priority(m, field, eq);
1133
1134 if (STR_IN_SET(field, "RuntimeDirectoryMode",
1135 "StateDirectoryMode",
1136 "CacheDirectoryMode",
1137 "LogsDirectoryMode",
1138 "ConfigurationDirectoryMode",
1139 "UMask"))
1140 return bus_append_parse_mode(m, field, eq);
1141
1142 if (streq(field, "TimerSlackNSec"))
1143 return bus_append_parse_nsec(m, field, eq);
1144
1145 if (streq(field, "LogRateLimitIntervalSec"))
1146 return bus_append_parse_sec_rename(m, field, eq);
1147
1148 if (STR_IN_SET(field, "LogRateLimitBurst",
1149 "TTYRows",
1150 "TTYColumns"))
1151 return bus_append_safe_atou(m, field, eq);
1152
1153 if (streq(field, "MountFlags"))
1154 return bus_append_mount_propagation_flag_from_string(m, field, eq);
1155
1156 if (STR_IN_SET(field, "Environment",
1157 "UnsetEnvironment",
1158 "PassEnvironment"))
1159 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
1160
1161 if (streq(field, "EnvironmentFile")) {
1162 if (isempty(eq))
1163 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1164 else
1165 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1166 eq[0] == '-' ? eq + 1 : eq,
1167 eq[0] == '-');
1168 if (r < 0)
1169 return bus_log_create_error(r);
1170
1171 return 1;
1172 }
1173
1174 if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
1175 r = sd_bus_message_open_container(m, 'r', "sv");
1176 if (r < 0)
1177 return bus_log_create_error(r);
1178
1179 r = sd_bus_message_append_basic(m, 's', field);
1180 if (r < 0)
1181 return bus_log_create_error(r);
1182
1183 r = sd_bus_message_open_container(m, 'v', "a(say)");
1184 if (r < 0)
1185 return bus_log_create_error(r);
1186
1187 if (isempty(eq))
1188 r = sd_bus_message_append(m, "a(say)", 0);
1189 else {
1190 _cleanup_free_ char *word = NULL;
1191 const char *p = eq;
1192
1193 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1194 if (r == -ENOMEM)
1195 return log_oom();
1196 if (r < 0)
1197 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
1198 if (r == 0 || !p)
1199 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
1200
1201 r = sd_bus_message_open_container(m, 'a', "(say)");
1202 if (r < 0)
1203 return bus_log_create_error(r);
1204
1205 r = sd_bus_message_open_container(m, 'r', "say");
1206 if (r < 0)
1207 return bus_log_create_error(r);
1208
1209 r = sd_bus_message_append(m, "s", word);
1210 if (r < 0)
1211 return bus_log_create_error(r);
1212
1213 if (streq(field, "SetCredentialEncrypted")) {
1214 _cleanup_free_ void *decoded = NULL;
1215 size_t decoded_size;
1216
1217 r = unbase64mem(p, &decoded, &decoded_size);
1218 if (r < 0)
1219 return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
1220
1221 r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
1222 } else {
1223 _cleanup_free_ char *unescaped = NULL;
1224 ssize_t l;
1225
1226 l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
1227 if (l < 0)
1228 return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
1229
1230 r = sd_bus_message_append_array(m, 'y', unescaped, l);
1231 }
1232 if (r < 0)
1233 return bus_log_create_error(r);
1234
1235 r = sd_bus_message_close_container(m);
1236 if (r < 0)
1237 return bus_log_create_error(r);
1238
1239 r = sd_bus_message_close_container(m);
1240 }
1241 if (r < 0)
1242 return bus_log_create_error(r);
1243
1244 r = sd_bus_message_close_container(m);
1245 if (r < 0)
1246 return bus_log_create_error(r);
1247
1248 r = sd_bus_message_close_container(m);
1249 if (r < 0)
1250 return bus_log_create_error(r);
1251
1252 return 1;
1253 }
1254
1255 if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
1256 r = sd_bus_message_open_container(m, 'r', "sv");
1257 if (r < 0)
1258 return bus_log_create_error(r);
1259
1260 r = sd_bus_message_append_basic(m, 's', field);
1261 if (r < 0)
1262 return bus_log_create_error(r);
1263
1264 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1265 if (r < 0)
1266 return bus_log_create_error(r);
1267
1268 if (isempty(eq))
1269 r = sd_bus_message_append(m, "a(ss)", 0);
1270 else {
1271 _cleanup_free_ char *word = NULL;
1272 const char *p = eq;
1273
1274 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1275 if (r == -ENOMEM)
1276 return log_oom();
1277 if (r < 0)
1278 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
1279 if (r == 0)
1280 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
1281
1282 if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
1283 p = eq;
1284
1285 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1286 }
1287 if (r < 0)
1288 return bus_log_create_error(r);
1289
1290 r = sd_bus_message_close_container(m);
1291 if (r < 0)
1292 return bus_log_create_error(r);
1293
1294 r = sd_bus_message_close_container(m);
1295 if (r < 0)
1296 return bus_log_create_error(r);
1297
1298 return 1;
1299 }
1300
1301 if (streq(field, "ImportCredential")) {
1302 if (isempty(eq))
1303 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
1304 else
1305 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
1306 if (r < 0)
1307 return bus_log_create_error(r);
1308
1309 return 1;
1310 }
1311
1312 if (streq(field, "LogExtraFields")) {
1313 r = sd_bus_message_open_container(m, 'r', "sv");
1314 if (r < 0)
1315 return bus_log_create_error(r);
1316
1317 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
1318 if (r < 0)
1319 return bus_log_create_error(r);
1320
1321 r = sd_bus_message_open_container(m, 'v', "aay");
1322 if (r < 0)
1323 return bus_log_create_error(r);
1324
1325 r = sd_bus_message_open_container(m, 'a', "ay");
1326 if (r < 0)
1327 return bus_log_create_error(r);
1328
1329 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
1330 if (r < 0)
1331 return bus_log_create_error(r);
1332
1333 r = sd_bus_message_close_container(m);
1334 if (r < 0)
1335 return bus_log_create_error(r);
1336
1337 r = sd_bus_message_close_container(m);
1338 if (r < 0)
1339 return bus_log_create_error(r);
1340
1341 r = sd_bus_message_close_container(m);
1342 if (r < 0)
1343 return bus_log_create_error(r);
1344
1345 return 1;
1346 }
1347
1348 if (streq(field, "LogFilterPatterns")) {
1349 r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1350 eq[0] != '~',
1351 eq[0] != '~' ? eq : eq + 1);
1352 if (r < 0)
1353 return bus_log_create_error(r);
1354
1355 return 1;
1356 }
1357
1358 if (STR_IN_SET(field, "StandardInput",
1359 "StandardOutput",
1360 "StandardError")) {
1361 const char *n, *appended;
1362
1363 if ((n = startswith(eq, "fd:"))) {
1364 appended = strjoina(field, "FileDescriptorName");
1365 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1366 } else if ((n = startswith(eq, "file:"))) {
1367 appended = strjoina(field, "File");
1368 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1369 } else if ((n = startswith(eq, "append:"))) {
1370 appended = strjoina(field, "FileToAppend");
1371 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1372 } else if ((n = startswith(eq, "truncate:"))) {
1373 appended = strjoina(field, "FileToTruncate");
1374 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1375 } else
1376 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
1377 if (r < 0)
1378 return bus_log_create_error(r);
1379
1380 return 1;
1381 }
1382
1383 if (streq(field, "StandardInputText")) {
1384 _cleanup_free_ char *unescaped = NULL;
1385 ssize_t l;
1386
1387 l = cunescape(eq, 0, &unescaped);
1388 if (l < 0)
1389 return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
1390
1391 if (!strextend(&unescaped, "\n"))
1392 return log_oom();
1393
1394 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1395 * programmatic interface anyway */
1396
1397 return bus_append_byte_array(m, field, unescaped, l + 1);
1398 }
1399
1400 if (streq(field, "StandardInputData")) {
1401 _cleanup_free_ void *decoded = NULL;
1402 size_t sz;
1403
1404 r = unbase64mem(eq, &decoded, &sz);
1405 if (r < 0)
1406 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
1407
1408 return bus_append_byte_array(m, field, decoded, sz);
1409 }
1410
1411 if ((suffix = startswith(field, "Limit"))) {
1412 int rl;
1413
1414 rl = rlimit_from_string(suffix);
1415 if (rl >= 0) {
1416 const char *sn;
1417 struct rlimit l;
1418
1419 r = rlimit_parse(rl, eq, &l);
1420 if (r < 0)
1421 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
1422
1423 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
1424 if (r < 0)
1425 return bus_log_create_error(r);
1426
1427 sn = strjoina(field, "Soft");
1428 r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
1429 if (r < 0)
1430 return bus_log_create_error(r);
1431
1432 return 1;
1433 }
1434 }
1435
1436 if (STR_IN_SET(field, "AppArmorProfile",
1437 "SmackProcessLabel")) {
1438 int ignore = 0;
1439 const char *s = eq;
1440
1441 if (eq[0] == '-') {
1442 ignore = 1;
1443 s = eq + 1;
1444 }
1445
1446 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
1447 if (r < 0)
1448 return bus_log_create_error(r);
1449
1450 return 1;
1451 }
1452
1453 if (STR_IN_SET(field, "CapabilityBoundingSet",
1454 "AmbientCapabilities")) {
1455 uint64_t sum = 0;
1456 bool invert = false;
1457 const char *p = eq;
1458
1459 if (*p == '~') {
1460 invert = true;
1461 p++;
1462 }
1463
1464 r = capability_set_from_string(p, &sum);
1465 if (r < 0)
1466 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
1467
1468 sum = invert ? ~sum : sum;
1469
1470 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
1471 if (r < 0)
1472 return bus_log_create_error(r);
1473
1474 return 1;
1475 }
1476
1477 if (streq(field, "CPUAffinity")) {
1478 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
1479 _cleanup_free_ uint8_t *array = NULL;
1480 size_t allocated;
1481
1482 if (eq && streq(eq, "numa")) {
1483 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1484 if (r < 0)
1485 return bus_log_create_error(r);
1486 return r;
1487 }
1488
1489 r = parse_cpu_set(eq, &cpuset);
1490 if (r < 0)
1491 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1492
1493 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1494 if (r < 0)
1495 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1496
1497 return bus_append_byte_array(m, field, array, allocated);
1498 }
1499
1500 if (streq(field, "NUMAPolicy")) {
1501 r = mpol_from_string(eq);
1502 if (r < 0)
1503 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1504
1505 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1506 if (r < 0)
1507 return bus_log_create_error(r);
1508
1509 return 1;
1510 }
1511
1512 if (streq(field, "NUMAMask")) {
1513 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1514 _cleanup_free_ uint8_t *array = NULL;
1515 size_t allocated;
1516
1517 if (eq && streq(eq, "all")) {
1518 r = numa_mask_add_all(&nodes);
1519 if (r < 0)
1520 return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1521 } else {
1522 r = parse_cpu_set(eq, &nodes);
1523 if (r < 0)
1524 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1525 }
1526
1527 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1528 if (r < 0)
1529 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1530
1531 return bus_append_byte_array(m, field, array, allocated);
1532 }
1533
1534 if (STR_IN_SET(field, "RestrictAddressFamilies",
1535 "RestrictFileSystems",
1536 "SystemCallFilter",
1537 "SystemCallLog",
1538 "RestrictNetworkInterfaces")) {
1539 int allow_list = 1;
1540 const char *p = eq;
1541
1542 if (*p == '~') {
1543 allow_list = 0;
1544 p++;
1545 }
1546
1547 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1548 if (r < 0)
1549 return bus_log_create_error(r);
1550
1551 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1552 if (r < 0)
1553 return bus_log_create_error(r);
1554
1555 r = sd_bus_message_open_container(m, 'v', "(bas)");
1556 if (r < 0)
1557 return bus_log_create_error(r);
1558
1559 r = sd_bus_message_open_container(m, 'r', "bas");
1560 if (r < 0)
1561 return bus_log_create_error(r);
1562
1563 r = sd_bus_message_append_basic(m, 'b', &allow_list);
1564 if (r < 0)
1565 return bus_log_create_error(r);
1566
1567 r = sd_bus_message_open_container(m, 'a', "s");
1568 if (r < 0)
1569 return bus_log_create_error(r);
1570
1571 for (;;) {
1572 _cleanup_free_ char *word = NULL;
1573
1574 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1575 if (r == 0)
1576 break;
1577 if (r == -ENOMEM)
1578 return log_oom();
1579 if (r < 0)
1580 return log_error_errno(r, "Invalid syntax: %s", eq);
1581
1582 r = sd_bus_message_append_basic(m, 's', word);
1583 if (r < 0)
1584 return bus_log_create_error(r);
1585 }
1586
1587 r = sd_bus_message_close_container(m);
1588 if (r < 0)
1589 return bus_log_create_error(r);
1590
1591 r = sd_bus_message_close_container(m);
1592 if (r < 0)
1593 return bus_log_create_error(r);
1594
1595 r = sd_bus_message_close_container(m);
1596 if (r < 0)
1597 return bus_log_create_error(r);
1598
1599 r = sd_bus_message_close_container(m);
1600 if (r < 0)
1601 return bus_log_create_error(r);
1602
1603 return 1;
1604 }
1605
1606 if (streq(field, "RestrictNamespaces")) {
1607 bool invert = false;
1608 unsigned long flags;
1609
1610 r = parse_boolean(eq);
1611 if (r > 0)
1612 flags = 0;
1613 else if (r == 0)
1614 flags = NAMESPACE_FLAGS_ALL;
1615 else {
1616 if (eq[0] == '~') {
1617 invert = true;
1618 eq++;
1619 }
1620
1621 r = namespace_flags_from_string(eq, &flags);
1622 if (r < 0)
1623 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1624 }
1625
1626 if (invert)
1627 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1628
1629 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1630 if (r < 0)
1631 return bus_log_create_error(r);
1632
1633 return 1;
1634 }
1635
1636 if (STR_IN_SET(field, "BindPaths",
1637 "BindReadOnlyPaths")) {
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(ssbt)");
1649 if (r < 0)
1650 return bus_log_create_error(r);
1651
1652 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1653 if (r < 0)
1654 return bus_log_create_error(r);
1655
1656 for (;;) {
1657 _cleanup_free_ char *source = NULL, *destination = NULL;
1658 char *s = NULL, *d = NULL;
1659 bool ignore_enoent = false;
1660 uint64_t flags = MS_REC;
1661
1662 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1663 if (r < 0)
1664 return log_error_errno(r, "Failed to parse argument: %m");
1665 if (r == 0)
1666 break;
1667
1668 s = source;
1669 if (s[0] == '-') {
1670 ignore_enoent = true;
1671 s++;
1672 }
1673
1674 if (p && p[-1] == ':') {
1675 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1676 if (r < 0)
1677 return log_error_errno(r, "Failed to parse argument: %m");
1678 if (r == 0)
1679 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1680 "Missing argument after ':': %s",
1681 eq);
1682
1683 d = destination;
1684
1685 if (p && p[-1] == ':') {
1686 _cleanup_free_ char *options = NULL;
1687
1688 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
1689 if (r < 0)
1690 return log_error_errno(r, "Failed to parse argument: %m");
1691
1692 if (isempty(options) || streq(options, "rbind"))
1693 flags = MS_REC;
1694 else if (streq(options, "norbind"))
1695 flags = 0;
1696 else
1697 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1698 "Unknown options: %s",
1699 eq);
1700 }
1701 } else
1702 d = s;
1703
1704 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1705 if (r < 0)
1706 return bus_log_create_error(r);
1707 }
1708
1709 r = sd_bus_message_close_container(m);
1710 if (r < 0)
1711 return bus_log_create_error(r);
1712
1713 r = sd_bus_message_close_container(m);
1714 if (r < 0)
1715 return bus_log_create_error(r);
1716
1717 r = sd_bus_message_close_container(m);
1718 if (r < 0)
1719 return bus_log_create_error(r);
1720
1721 return 1;
1722 }
1723
1724 if (streq(field, "TemporaryFileSystem")) {
1725 const char *p = eq;
1726
1727 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1728 if (r < 0)
1729 return bus_log_create_error(r);
1730
1731 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1732 if (r < 0)
1733 return bus_log_create_error(r);
1734
1735 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1736 if (r < 0)
1737 return bus_log_create_error(r);
1738
1739 r = sd_bus_message_open_container(m, 'a', "(ss)");
1740 if (r < 0)
1741 return bus_log_create_error(r);
1742
1743 for (;;) {
1744 _cleanup_free_ char *word = NULL, *path = NULL;
1745 const char *w;
1746
1747 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1748 if (r < 0)
1749 return log_error_errno(r, "Failed to parse argument: %m");
1750 if (r == 0)
1751 break;
1752
1753 w = word;
1754 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1755 if (r < 0)
1756 return log_error_errno(r, "Failed to parse argument: %m");
1757 if (r == 0)
1758 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1759 "Failed to parse argument: %s",
1760 p);
1761
1762 r = sd_bus_message_append(m, "(ss)", path, w);
1763 if (r < 0)
1764 return bus_log_create_error(r);
1765 }
1766
1767 r = sd_bus_message_close_container(m);
1768 if (r < 0)
1769 return bus_log_create_error(r);
1770
1771 r = sd_bus_message_close_container(m);
1772 if (r < 0)
1773 return bus_log_create_error(r);
1774
1775 r = sd_bus_message_close_container(m);
1776 if (r < 0)
1777 return bus_log_create_error(r);
1778
1779 return 1;
1780 }
1781
1782 if (streq(field, "RootHash")) {
1783 _cleanup_free_ void *roothash_decoded = NULL;
1784 size_t roothash_decoded_size = 0;
1785
1786 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1787 if (path_is_absolute(eq))
1788 return bus_append_string(m, "RootHashPath", eq);
1789
1790 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1791 r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
1792 if (r < 0)
1793 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1794 if (roothash_decoded_size < sizeof(sd_id128_t))
1795 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
1796
1797 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1798 }
1799
1800 if (streq(field, "RootHashSignature")) {
1801 _cleanup_free_ void *roothash_sig_decoded = NULL;
1802 char *value;
1803 size_t roothash_sig_decoded_size = 0;
1804
1805 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1806 if (path_is_absolute(eq))
1807 return bus_append_string(m, "RootHashSignaturePath", eq);
1808
1809 if (!(value = startswith(eq, "base64:")))
1810 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
1811
1812 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1813 r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
1814 if (r < 0)
1815 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1816
1817 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1818 }
1819
1820 if (streq(field, "RootImageOptions")) {
1821 _cleanup_strv_free_ char **l = NULL;
1822 const char *p = eq;
1823
1824 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1825 if (r < 0)
1826 return bus_log_create_error(r);
1827
1828 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1829 if (r < 0)
1830 return bus_log_create_error(r);
1831
1832 r = sd_bus_message_open_container(m, 'v', "a(ss)");
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 r = strv_split_colon_pairs(&l, p);
1841 if (r < 0)
1842 return log_error_errno(r, "Failed to parse argument: %m");
1843
1844 STRV_FOREACH_PAIR(first, second, l) {
1845 r = sd_bus_message_append(m, "(ss)",
1846 !isempty(*second) ? *first : "root",
1847 !isempty(*second) ? *second : *first);
1848 if (r < 0)
1849 return bus_log_create_error(r);
1850 }
1851
1852 r = sd_bus_message_close_container(m);
1853 if (r < 0)
1854 return bus_log_create_error(r);
1855
1856 r = sd_bus_message_close_container(m);
1857 if (r < 0)
1858 return bus_log_create_error(r);
1859
1860 r = sd_bus_message_close_container(m);
1861 if (r < 0)
1862 return bus_log_create_error(r);
1863
1864 return 1;
1865 }
1866
1867 if (streq(field, "MountImages")) {
1868 const char *p = eq;
1869
1870 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1871 if (r < 0)
1872 return bus_log_create_error(r);
1873
1874 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1875 if (r < 0)
1876 return bus_log_create_error(r);
1877
1878 r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
1879 if (r < 0)
1880 return bus_log_create_error(r);
1881
1882 r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
1883 if (r < 0)
1884 return bus_log_create_error(r);
1885
1886 for (;;) {
1887 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
1888 const char *q = NULL, *source = NULL;
1889 bool permissive = false;
1890
1891 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1892 if (r < 0)
1893 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1894 if (r == 0)
1895 break;
1896
1897 q = tuple;
1898 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
1899 if (r < 0)
1900 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1901 if (r == 0)
1902 continue;
1903
1904 source = first;
1905 if (source[0] == '-') {
1906 permissive = true;
1907 source++;
1908 }
1909
1910 if (isempty(second))
1911 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1912 "Missing argument after ':': %s",
1913 eq);
1914
1915 r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
1916 if (r < 0)
1917 return bus_log_create_error(r);
1918
1919 r = sd_bus_message_append(m, "ssb", source, second, permissive);
1920 if (r < 0)
1921 return bus_log_create_error(r);
1922
1923 r = sd_bus_message_open_container(m, 'a', "(ss)");
1924 if (r < 0)
1925 return bus_log_create_error(r);
1926
1927 for (;;) {
1928 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1929
1930 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
1931 if (r < 0)
1932 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
1933 if (r == 0)
1934 break;
1935 /* Single set of options, applying to the root partition/single filesystem */
1936 if (r == 1) {
1937 r = sd_bus_message_append(m, "(ss)", "root", partition);
1938 if (r < 0)
1939 return bus_log_create_error(r);
1940
1941 break;
1942 }
1943
1944 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1945 if (r < 0)
1946 return bus_log_create_error(r);
1947 }
1948
1949 r = sd_bus_message_close_container(m);
1950 if (r < 0)
1951 return bus_log_create_error(r);
1952
1953 r = sd_bus_message_close_container(m);
1954 if (r < 0)
1955 return bus_log_create_error(r);
1956 }
1957
1958 r = sd_bus_message_close_container(m);
1959 if (r < 0)
1960 return bus_log_create_error(r);
1961
1962 r = sd_bus_message_close_container(m);
1963 if (r < 0)
1964 return bus_log_create_error(r);
1965
1966 r = sd_bus_message_close_container(m);
1967 if (r < 0)
1968 return bus_log_create_error(r);
1969
1970 return 1;
1971 }
1972
1973 if (streq(field, "ExtensionImages")) {
1974 const char *p = eq;
1975
1976 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1977 if (r < 0)
1978 return bus_log_create_error(r);
1979
1980 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1981 if (r < 0)
1982 return bus_log_create_error(r);
1983
1984 r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
1985 if (r < 0)
1986 return bus_log_create_error(r);
1987
1988 r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
1989 if (r < 0)
1990 return bus_log_create_error(r);
1991
1992 for (;;) {
1993 _cleanup_free_ char *source = NULL, *tuple = NULL;
1994 const char *q = NULL, *s = NULL;
1995 bool permissive = false;
1996
1997 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1998 if (r < 0)
1999 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
2000 if (r == 0)
2001 break;
2002
2003 q = tuple;
2004 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
2005 if (r < 0)
2006 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
2007 if (r == 0)
2008 continue;
2009
2010 s = source;
2011 if (s[0] == '-') {
2012 permissive = true;
2013 s++;
2014 }
2015
2016 r = sd_bus_message_open_container(m, 'r', "sba(ss)");
2017 if (r < 0)
2018 return bus_log_create_error(r);
2019
2020 r = sd_bus_message_append(m, "sb", s, permissive);
2021 if (r < 0)
2022 return bus_log_create_error(r);
2023
2024 r = sd_bus_message_open_container(m, 'a', "(ss)");
2025 if (r < 0)
2026 return bus_log_create_error(r);
2027
2028 for (;;) {
2029 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2030
2031 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
2032 if (r < 0)
2033 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
2034 if (r == 0)
2035 break;
2036 /* Single set of options, applying to the root partition/single filesystem */
2037 if (r == 1) {
2038 r = sd_bus_message_append(m, "(ss)", "root", partition);
2039 if (r < 0)
2040 return bus_log_create_error(r);
2041
2042 break;
2043 }
2044
2045 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2046 if (r < 0)
2047 return bus_log_create_error(r);
2048 }
2049
2050 r = sd_bus_message_close_container(m);
2051 if (r < 0)
2052 return bus_log_create_error(r);
2053
2054 r = sd_bus_message_close_container(m);
2055 if (r < 0)
2056 return bus_log_create_error(r);
2057 }
2058
2059 r = sd_bus_message_close_container(m);
2060 if (r < 0)
2061 return bus_log_create_error(r);
2062
2063 r = sd_bus_message_close_container(m);
2064 if (r < 0)
2065 return bus_log_create_error(r);
2066
2067 r = sd_bus_message_close_container(m);
2068 if (r < 0)
2069 return bus_log_create_error(r);
2070
2071 return 1;
2072 }
2073
2074 if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
2075 _cleanup_strv_free_ char **symlinks = NULL, **sources = NULL;
2076 const char *p = eq;
2077
2078 /* Adding new directories is supported from both *DirectorySymlink methods and the
2079 * older ones, so first parse the input, and if we are given a new-style src:dst
2080 * tuple use the new method, else use the old one. */
2081
2082 for (;;) {
2083 _cleanup_free_ char *tuple = NULL, *source = NULL, *destination = NULL;
2084
2085 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
2086 if (r < 0)
2087 return log_error_errno(r, "Failed to parse argument: %m");
2088 if (r == 0)
2089 break;
2090
2091 const char *t = tuple;
2092 r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination);
2093 if (r <= 0)
2094 return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
2095
2096 path_simplify(source);
2097
2098 if (isempty(destination)) {
2099 r = strv_consume(&sources, TAKE_PTR(source));
2100 if (r < 0)
2101 return bus_log_create_error(r);
2102 } else {
2103 path_simplify(destination);
2104
2105 r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(destination));
2106 if (r < 0)
2107 return log_oom();
2108 }
2109 }
2110
2111 if (!strv_isempty(sources)) {
2112 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2113 if (r < 0)
2114 return bus_log_create_error(r);
2115
2116 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2117 if (r < 0)
2118 return bus_log_create_error(r);
2119
2120 r = sd_bus_message_open_container(m, 'v', "as");
2121 if (r < 0)
2122 return bus_log_create_error(r);
2123
2124 r = sd_bus_message_append_strv(m, sources);
2125 if (r < 0)
2126 return bus_log_create_error(r);
2127
2128 r = sd_bus_message_close_container(m);
2129 if (r < 0)
2130 return bus_log_create_error(r);
2131
2132 r = sd_bus_message_close_container(m);
2133 if (r < 0)
2134 return bus_log_create_error(r);
2135 }
2136
2137 /* For State and Runtime directories we support an optional destination parameter, which
2138 * will be used to create a symlink to the source. But it is new so we cannot change the
2139 * old DBUS signatures, so append a new message type. */
2140 if (!strv_isempty(symlinks)) {
2141 const char *symlink_field;
2142
2143 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2144 if (r < 0)
2145 return bus_log_create_error(r);
2146
2147 if (streq(field, "StateDirectory"))
2148 symlink_field = "StateDirectorySymlink";
2149 else if (streq(field, "RuntimeDirectory"))
2150 symlink_field = "RuntimeDirectorySymlink";
2151 else if (streq(field, "CacheDirectory"))
2152 symlink_field = "CacheDirectorySymlink";
2153 else if (streq(field, "LogsDirectory"))
2154 symlink_field = "LogsDirectorySymlink";
2155 else
2156 assert_not_reached();
2157
2158 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
2159 if (r < 0)
2160 return bus_log_create_error(r);
2161
2162 r = sd_bus_message_open_container(m, 'v', "a(sst)");
2163 if (r < 0)
2164 return bus_log_create_error(r);
2165
2166 r = sd_bus_message_open_container(m, 'a', "(sst)");
2167 if (r < 0)
2168 return bus_log_create_error(r);
2169
2170 STRV_FOREACH_PAIR(source, destination, symlinks) {
2171 r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
2172 if (r < 0)
2173 return bus_log_create_error(r);
2174 }
2175
2176 r = sd_bus_message_close_container(m);
2177 if (r < 0)
2178 return bus_log_create_error(r);
2179
2180 r = sd_bus_message_close_container(m);
2181 if (r < 0)
2182 return bus_log_create_error(r);
2183
2184 r = sd_bus_message_close_container(m);
2185 if (r < 0)
2186 return bus_log_create_error(r);
2187 }
2188
2189 return 1;
2190 }
2191
2192 return 0;
2193 }
2194
2195 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
2196 if (streq(field, "KillMode"))
2197 return bus_append_string(m, field, eq);
2198
2199 if (STR_IN_SET(field, "SendSIGHUP",
2200 "SendSIGKILL"))
2201 return bus_append_parse_boolean(m, field, eq);
2202
2203 if (STR_IN_SET(field, "KillSignal",
2204 "RestartKillSignal",
2205 "FinalKillSignal",
2206 "WatchdogSignal",
2207 "ReloadSignal"))
2208 return bus_append_signal_from_string(m, field, eq);
2209
2210 return 0;
2211 }
2212
2213 static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
2214
2215 if (STR_IN_SET(field, "What",
2216 "Where",
2217 "Options",
2218 "Type"))
2219 return bus_append_string(m, field, eq);
2220
2221 if (streq(field, "TimeoutSec"))
2222 return bus_append_parse_sec_rename(m, field, eq);
2223
2224 if (streq(field, "DirectoryMode"))
2225 return bus_append_parse_mode(m, field, eq);
2226
2227 if (STR_IN_SET(field, "SloppyOptions",
2228 "LazyUnmount",
2229 "ForceUnmount",
2230 "ReadwriteOnly"))
2231 return bus_append_parse_boolean(m, field, eq);
2232
2233 return 0;
2234 }
2235
2236 static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
2237 int r;
2238
2239 if (streq(field, "MakeDirectory"))
2240 return bus_append_parse_boolean(m, field, eq);
2241
2242 if (streq(field, "DirectoryMode"))
2243 return bus_append_parse_mode(m, field, eq);
2244
2245 if (STR_IN_SET(field, "PathExists",
2246 "PathExistsGlob",
2247 "PathChanged",
2248 "PathModified",
2249 "DirectoryNotEmpty")) {
2250 if (isempty(eq))
2251 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
2252 else
2253 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
2254 if (r < 0)
2255 return bus_log_create_error(r);
2256
2257 return 1;
2258 }
2259
2260 if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
2261 return bus_append_safe_atou(m, field, eq);
2262
2263 if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
2264 return bus_append_parse_sec_rename(m, field, eq);
2265
2266 return 0;
2267 }
2268
2269 static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
2270 if (streq(field, "RuntimeMaxSec"))
2271 return bus_append_parse_sec_rename(m, field, eq);
2272
2273 if (streq(field, "RuntimeRandomizedExtraSec"))
2274 return bus_append_parse_sec_rename(m, field, eq);
2275
2276 if (streq(field, "TimeoutStopSec"))
2277 return bus_append_parse_sec_rename(m, field, eq);
2278
2279 /* Scope units don't have execution context but we still want to allow setting these two,
2280 * so let's handle them separately. */
2281 if (STR_IN_SET(field, "User", "Group"))
2282 return bus_append_string(m, field, eq);
2283
2284 if (streq(field, "OOMPolicy"))
2285 return bus_append_string(m, field, eq);
2286
2287 return 0;
2288 }
2289
2290 static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
2291 int r;
2292
2293 if (STR_IN_SET(field, "PIDFile",
2294 "Type",
2295 "ExitType",
2296 "Restart",
2297 "RestartMode",
2298 "BusName",
2299 "NotifyAccess",
2300 "USBFunctionDescriptors",
2301 "USBFunctionStrings",
2302 "OOMPolicy",
2303 "TimeoutStartFailureMode",
2304 "TimeoutStopFailureMode",
2305 "FileDescriptorStorePreserve"))
2306 return bus_append_string(m, field, eq);
2307
2308 if (STR_IN_SET(field, "PermissionsStartOnly",
2309 "RootDirectoryStartOnly",
2310 "RemainAfterExit",
2311 "GuessMainPID"))
2312 return bus_append_parse_boolean(m, field, eq);
2313
2314 if (STR_IN_SET(field, "RestartSec",
2315 "RestartMaxDelaySec",
2316 "TimeoutStartSec",
2317 "TimeoutStopSec",
2318 "TimeoutAbortSec",
2319 "RuntimeMaxSec",
2320 "RuntimeRandomizedExtraSec",
2321 "WatchdogSec"))
2322 return bus_append_parse_sec_rename(m, field, eq);
2323
2324 if (streq(field, "TimeoutSec")) {
2325 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2326 if (r < 0)
2327 return r;
2328
2329 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2330 }
2331
2332 if (STR_IN_SET(field, "FileDescriptorStoreMax",
2333 "RestartSteps"))
2334 return bus_append_safe_atou(m, field, eq);
2335
2336 if (STR_IN_SET(field, "ExecCondition",
2337 "ExecStartPre",
2338 "ExecStart",
2339 "ExecStartPost",
2340 "ExecConditionEx",
2341 "ExecStartPreEx",
2342 "ExecStartEx",
2343 "ExecStartPostEx",
2344 "ExecReload",
2345 "ExecStop",
2346 "ExecStopPost",
2347 "ExecReloadEx",
2348 "ExecStopEx",
2349 "ExecStopPostEx"))
2350 return bus_append_exec_command(m, field, eq);
2351
2352 if (STR_IN_SET(field, "RestartPreventExitStatus",
2353 "RestartForceExitStatus",
2354 "SuccessExitStatus")) {
2355 _cleanup_free_ int *status = NULL, *signal = NULL;
2356 size_t n_status = 0, n_signal = 0;
2357 const char *p;
2358
2359 for (p = eq;;) {
2360 _cleanup_free_ char *word = NULL;
2361
2362 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2363 if (r == 0)
2364 break;
2365 if (r == -ENOMEM)
2366 return log_oom();
2367 if (r < 0)
2368 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2369
2370 /* We need to call exit_status_from_string() first, because we want
2371 * to parse numbers as exit statuses, not signals. */
2372
2373 r = exit_status_from_string(word);
2374 if (r >= 0) {
2375 assert(r >= 0 && r < 256);
2376
2377 status = reallocarray(status, n_status + 1, sizeof(int));
2378 if (!status)
2379 return log_oom();
2380
2381 status[n_status++] = r;
2382
2383 } else if ((r = signal_from_string(word)) >= 0) {
2384 signal = reallocarray(signal, n_signal + 1, sizeof(int));
2385 if (!signal)
2386 return log_oom();
2387
2388 signal[n_signal++] = r;
2389
2390 } else
2391 /* original r from exit_status_to_string() */
2392 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2393 word, field);
2394 }
2395
2396 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2397 if (r < 0)
2398 return bus_log_create_error(r);
2399
2400 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2401 if (r < 0)
2402 return bus_log_create_error(r);
2403
2404 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2405 if (r < 0)
2406 return bus_log_create_error(r);
2407
2408 r = sd_bus_message_open_container(m, 'r', "aiai");
2409 if (r < 0)
2410 return bus_log_create_error(r);
2411
2412 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
2413 if (r < 0)
2414 return bus_log_create_error(r);
2415
2416 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
2417 if (r < 0)
2418 return bus_log_create_error(r);
2419
2420 r = sd_bus_message_close_container(m);
2421 if (r < 0)
2422 return bus_log_create_error(r);
2423
2424 r = sd_bus_message_close_container(m);
2425 if (r < 0)
2426 return bus_log_create_error(r);
2427
2428 r = sd_bus_message_close_container(m);
2429 if (r < 0)
2430 return bus_log_create_error(r);
2431
2432 return 1;
2433 }
2434
2435 if (streq(field, "OpenFile"))
2436 return bus_append_open_file(m, field, eq);
2437
2438 return 0;
2439 }
2440
2441 static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2442 int r;
2443
2444 if (STR_IN_SET(field, "Accept",
2445 "FlushPending",
2446 "Writable",
2447 "KeepAlive",
2448 "NoDelay",
2449 "FreeBind",
2450 "Transparent",
2451 "Broadcast",
2452 "PassCredentials",
2453 "PassSecurity",
2454 "PassPacketInfo",
2455 "ReusePort",
2456 "RemoveOnStop",
2457 "SELinuxContextFromNet"))
2458 return bus_append_parse_boolean(m, field, eq);
2459
2460 if (STR_IN_SET(field, "Priority",
2461 "IPTTL",
2462 "Mark"))
2463 return bus_append_safe_atoi(m, field, eq);
2464
2465 if (streq(field, "IPTOS"))
2466 return bus_append_ip_tos_from_string(m, field, eq);
2467
2468 if (STR_IN_SET(field, "Backlog",
2469 "MaxConnections",
2470 "MaxConnectionsPerSource",
2471 "KeepAliveProbes",
2472 "TriggerLimitBurst",
2473 "PollLimitBurst"))
2474 return bus_append_safe_atou(m, field, eq);
2475
2476 if (STR_IN_SET(field, "SocketMode",
2477 "DirectoryMode"))
2478 return bus_append_parse_mode(m, field, eq);
2479
2480 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2481 "MessageQueueMessageSize"))
2482 return bus_append_safe_atoi64(m, field, eq);
2483
2484 if (STR_IN_SET(field, "TimeoutSec",
2485 "KeepAliveTimeSec",
2486 "KeepAliveIntervalSec",
2487 "DeferAcceptSec",
2488 "TriggerLimitIntervalSec",
2489 "PollLimitIntervalSec"))
2490 return bus_append_parse_sec_rename(m, field, eq);
2491
2492 if (STR_IN_SET(field, "ReceiveBuffer",
2493 "SendBuffer",
2494 "PipeSize"))
2495 return bus_append_parse_size(m, field, eq, 1024);
2496
2497 if (STR_IN_SET(field, "ExecStartPre",
2498 "ExecStartPost",
2499 "ExecReload",
2500 "ExecStopPost"))
2501 return bus_append_exec_command(m, field, eq);
2502
2503 if (STR_IN_SET(field, "SmackLabel",
2504 "SmackLabelIPIn",
2505 "SmackLabelIPOut",
2506 "TCPCongestion",
2507 "BindToDevice",
2508 "BindIPv6Only",
2509 "FileDescriptorName",
2510 "SocketUser",
2511 "SocketGroup",
2512 "Timestamping"))
2513 return bus_append_string(m, field, eq);
2514
2515 if (streq(field, "Symlinks"))
2516 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
2517
2518 if (streq(field, "SocketProtocol"))
2519 return bus_append_parse_ip_protocol(m, field, eq);
2520
2521 if (STR_IN_SET(field, "ListenStream",
2522 "ListenDatagram",
2523 "ListenSequentialPacket",
2524 "ListenNetlink",
2525 "ListenSpecial",
2526 "ListenMessageQueue",
2527 "ListenFIFO",
2528 "ListenUSBFunction")) {
2529 if (isempty(eq))
2530 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2531 else
2532 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
2533 if (r < 0)
2534 return bus_log_create_error(r);
2535
2536 return 1;
2537 }
2538
2539 return 0;
2540 }
2541 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
2542 int r;
2543
2544 if (STR_IN_SET(field, "WakeSystem",
2545 "RemainAfterElapse",
2546 "Persistent",
2547 "OnTimezoneChange",
2548 "OnClockChange",
2549 "FixedRandomDelay"))
2550 return bus_append_parse_boolean(m, field, eq);
2551
2552 if (STR_IN_SET(field, "AccuracySec",
2553 "RandomizedDelaySec"))
2554 return bus_append_parse_sec_rename(m, field, eq);
2555
2556 if (STR_IN_SET(field, "OnActiveSec",
2557 "OnBootSec",
2558 "OnStartupSec",
2559 "OnUnitActiveSec",
2560 "OnUnitInactiveSec")) {
2561 if (isempty(eq))
2562 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2563 else {
2564 usec_t t;
2565 r = parse_sec(eq, &t);
2566 if (r < 0)
2567 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
2568
2569 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2570 }
2571 if (r < 0)
2572 return bus_log_create_error(r);
2573
2574 return 1;
2575 }
2576
2577 if (streq(field, "OnCalendar")) {
2578 if (isempty(eq))
2579 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2580 else
2581 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2582 if (r < 0)
2583 return bus_log_create_error(r);
2584
2585 return 1;
2586 }
2587
2588 return 0;
2589 }
2590
2591 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
2592 ConditionType t = _CONDITION_TYPE_INVALID;
2593 bool is_condition = false;
2594 int r;
2595
2596 if (STR_IN_SET(field, "Description",
2597 "SourcePath",
2598 "OnFailureJobMode",
2599 "JobTimeoutAction",
2600 "JobTimeoutRebootArgument",
2601 "StartLimitAction",
2602 "FailureAction",
2603 "SuccessAction",
2604 "RebootArgument",
2605 "CollectMode"))
2606 return bus_append_string(m, field, eq);
2607
2608 if (STR_IN_SET(field, "StopWhenUnneeded",
2609 "RefuseManualStart",
2610 "RefuseManualStop",
2611 "AllowIsolate",
2612 "IgnoreOnIsolate",
2613 "SurviveFinalKillSignal",
2614 "DefaultDependencies"))
2615 return bus_append_parse_boolean(m, field, eq);
2616
2617 if (STR_IN_SET(field, "JobTimeoutSec",
2618 "JobRunningTimeoutSec",
2619 "StartLimitIntervalSec"))
2620 return bus_append_parse_sec_rename(m, field, eq);
2621
2622 if (streq(field, "StartLimitBurst"))
2623 return bus_append_safe_atou(m, field, eq);
2624
2625 if (STR_IN_SET(field, "SuccessActionExitStatus",
2626 "FailureActionExitStatus")) {
2627 if (isempty(eq))
2628 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2629 else {
2630 uint8_t u;
2631
2632 r = safe_atou8(eq, &u);
2633 if (r < 0)
2634 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2635
2636 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2637 }
2638 if (r < 0)
2639 return bus_log_create_error(r);
2640
2641 return 1;
2642 }
2643
2644 if (unit_dependency_from_string(field) >= 0 ||
2645 STR_IN_SET(field, "Documentation",
2646 "RequiresMountsFor",
2647 "WantsMountsFor",
2648 "Markers"))
2649 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
2650
2651 t = condition_type_from_string(field);
2652 if (t >= 0)
2653 is_condition = true;
2654 else
2655 t = assert_type_from_string(field);
2656 if (t >= 0) {
2657 if (isempty(eq))
2658 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2659 else {
2660 const char *p = eq;
2661 int trigger, negate;
2662
2663 trigger = *p == '|';
2664 if (trigger)
2665 p++;
2666
2667 negate = *p == '!';
2668 if (negate)
2669 p++;
2670
2671 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2672 field, trigger, negate, p);
2673 }
2674 if (r < 0)
2675 return bus_log_create_error(r);
2676
2677 return 1;
2678 }
2679
2680 return 0;
2681 }
2682
2683 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2684 const char *eq, *field;
2685 int r;
2686
2687 assert(m);
2688 assert(assignment);
2689
2690 eq = strchr(assignment, '=');
2691 if (!eq)
2692 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2693 "Not an assignment: %s", assignment);
2694
2695 field = strndupa_safe(assignment, eq - assignment);
2696 eq++;
2697
2698 switch (t) {
2699 case UNIT_SERVICE:
2700 r = bus_append_cgroup_property(m, field, eq);
2701 if (r != 0)
2702 return r;
2703
2704 r = bus_append_execute_property(m, field, eq);
2705 if (r != 0)
2706 return r;
2707
2708 r = bus_append_kill_property(m, field, eq);
2709 if (r != 0)
2710 return r;
2711
2712 r = bus_append_service_property(m, field, eq);
2713 if (r != 0)
2714 return r;
2715 break;
2716
2717 case UNIT_SOCKET:
2718 r = bus_append_cgroup_property(m, field, eq);
2719 if (r != 0)
2720 return r;
2721
2722 r = bus_append_execute_property(m, field, eq);
2723 if (r != 0)
2724 return r;
2725
2726 r = bus_append_kill_property(m, field, eq);
2727 if (r != 0)
2728 return r;
2729
2730 r = bus_append_socket_property(m, field, eq);
2731 if (r != 0)
2732 return r;
2733 break;
2734
2735 case UNIT_TIMER:
2736 r = bus_append_timer_property(m, field, eq);
2737 if (r != 0)
2738 return r;
2739 break;
2740
2741 case UNIT_PATH:
2742 r = bus_append_path_property(m, field, eq);
2743 if (r != 0)
2744 return r;
2745 break;
2746
2747 case UNIT_SLICE:
2748 r = bus_append_cgroup_property(m, field, eq);
2749 if (r != 0)
2750 return r;
2751 break;
2752
2753 case UNIT_SCOPE:
2754 r = bus_append_cgroup_property(m, field, eq);
2755 if (r != 0)
2756 return r;
2757
2758 r = bus_append_kill_property(m, field, eq);
2759 if (r != 0)
2760 return r;
2761
2762 r = bus_append_scope_property(m, field, eq);
2763 if (r != 0)
2764 return r;
2765 break;
2766
2767 case UNIT_MOUNT:
2768 r = bus_append_cgroup_property(m, field, eq);
2769 if (r != 0)
2770 return r;
2771
2772 r = bus_append_execute_property(m, field, eq);
2773 if (r != 0)
2774 return r;
2775
2776 r = bus_append_kill_property(m, field, eq);
2777 if (r != 0)
2778 return r;
2779
2780 r = bus_append_mount_property(m, field, eq);
2781 if (r != 0)
2782 return r;
2783
2784 break;
2785
2786 case UNIT_AUTOMOUNT:
2787 r = bus_append_automount_property(m, field, eq);
2788 if (r != 0)
2789 return r;
2790
2791 break;
2792
2793 case UNIT_TARGET:
2794 case UNIT_DEVICE:
2795 case UNIT_SWAP:
2796 break;
2797
2798 default:
2799 assert_not_reached();
2800 }
2801
2802 r = bus_append_unit_property(m, field, eq);
2803 if (r != 0)
2804 return r;
2805
2806 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2807 "Unknown assignment: %s", assignment);
2808 }
2809
2810 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
2811 int r;
2812
2813 assert(m);
2814
2815 STRV_FOREACH(i, l) {
2816 r = bus_append_unit_property_assignment(m, t, *i);
2817 if (r < 0)
2818 return r;
2819 }
2820
2821 return 0;
2822 }
2823
2824 int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
2825 assert(m);
2826
2827 if (!pidref_is_set(pidref))
2828 return -ESRCH;
2829
2830 if (pidref->fd >= 0 && allow_pidfd)
2831 return sd_bus_message_append(
2832 m, "(sv)",
2833 "PIDFDs", "ah", 1, pidref->fd);
2834
2835 return sd_bus_message_append(
2836 m, "(sv)",
2837 "PIDs", "au", 1, pidref->pid);
2838 }
2839
2840 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
2841 const char *type, *path, *source;
2842 InstallChange *changes = NULL;
2843 size_t n_changes = 0;
2844 int r;
2845
2846 CLEANUP_ARRAY(changes, n_changes, install_changes_free);
2847
2848 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2849 if (r < 0)
2850 return bus_log_parse_error(r);
2851
2852 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2853 InstallChangeType t;
2854
2855 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2856 * negative. */
2857 t = install_change_type_from_string(type);
2858 if (t < 0) {
2859 log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2860 type, path);
2861 continue;
2862 }
2863
2864 r = install_changes_add(&changes, &n_changes, t, path, source);
2865 if (r < 0)
2866 return r;
2867 }
2868 if (r < 0)
2869 return bus_log_parse_error(r);
2870
2871 r = sd_bus_message_exit_container(m);
2872 if (r < 0)
2873 return bus_log_parse_error(r);
2874
2875 install_changes_dump(0, NULL, changes, n_changes, quiet);
2876
2877 return 0;
2878 }
2879
2880 int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2881 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2882 _cleanup_free_ char *path = NULL;
2883 int r;
2884
2885 path = unit_dbus_path_from_name(name);
2886 if (!path)
2887 return log_oom();
2888
2889 /* This function warns on its own, because otherwise it'd be awkward to pass
2890 * the dbus error message around. */
2891
2892 r = sd_bus_get_property_string(
2893 bus,
2894 "org.freedesktop.systemd1",
2895 path,
2896 "org.freedesktop.systemd1.Unit",
2897 "LoadState",
2898 &error,
2899 load_state);
2900 if (r < 0)
2901 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2902
2903 return 0;
2904 }
2905
2906 int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2907 int r;
2908
2909 /* First, order by machine */
2910 r = strcasecmp_ptr(a->machine, b->machine);
2911 if (r != 0)
2912 return r;
2913
2914 /* Second, order by unit type */
2915 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2916 if (r != 0)
2917 return r;
2918
2919 /* Third, order by name */
2920 return strcasecmp(a->id, b->id);
2921 }
2922
2923 int bus_service_manager_reload(sd_bus *bus) {
2924 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2925 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2926 int r;
2927
2928 assert(bus);
2929
2930 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
2931 if (r < 0)
2932 return bus_log_create_error(r);
2933
2934 /* Reloading the daemon may take long, hence set a longer timeout here */
2935 r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
2936 if (r < 0)
2937 return log_error_errno(r, "Failed to reload service manager: %s", bus_error_message(&error, r));
2938
2939 return 0;
2940 }
2941
2942 /* Wait for 1.5 seconds at maximum for freeze operation */
2943 #define FREEZE_BUS_CALL_TIMEOUT (1500 * USEC_PER_MSEC)
2944
2945 int unit_freezer_new(const char *name, UnitFreezer *ret) {
2946 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2947 _cleanup_free_ char *namedup = NULL;
2948 int r;
2949
2950 assert(name);
2951 assert(ret);
2952
2953 namedup = strdup(name);
2954 if (!namedup)
2955 return log_oom_debug();
2956
2957 r = bus_connect_system_systemd(&bus);
2958 if (r < 0)
2959 return log_debug_errno(r, "Failed to open connection to systemd: %m");
2960
2961 (void) sd_bus_set_method_call_timeout(bus, FREEZE_BUS_CALL_TIMEOUT);
2962
2963 *ret = (UnitFreezer) {
2964 .name = TAKE_PTR(namedup),
2965 .bus = TAKE_PTR(bus),
2966 };
2967 return 0;
2968 }
2969
2970 void unit_freezer_done(UnitFreezer *f) {
2971 assert(f);
2972
2973 f->name = mfree(f->name);
2974 f->bus = sd_bus_flush_close_unref(f->bus);
2975 }
2976
2977 static int unit_freezer_action(UnitFreezer *f, bool freeze) {
2978 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2979 int r;
2980
2981 assert(f);
2982 assert(f->name);
2983 assert(f->bus);
2984
2985 r = bus_call_method(f->bus, bus_systemd_mgr,
2986 freeze ? "FreezeUnit" : "ThawUnit",
2987 &error,
2988 /* reply = */ NULL,
2989 "s",
2990 f->name);
2991 if (r < 0)
2992 return log_debug_errno(r, "Failed to %s unit %s: %s",
2993 freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
2994
2995 return 0;
2996 }
2997
2998 int unit_freezer_freeze(UnitFreezer *f) {
2999 return unit_freezer_action(f, true);
3000 }
3001
3002 int unit_freezer_thaw(UnitFreezer *f) {
3003 return unit_freezer_action(f, false);
3004 }
3005
3006 int unit_freezer_new_freeze(const char *name, UnitFreezer *ret) {
3007 _cleanup_(unit_freezer_done) UnitFreezer f = {};
3008 int r;
3009
3010 assert(name);
3011 assert(ret);
3012
3013 r = unit_freezer_new(name, &f);
3014 if (r < 0)
3015 return r;
3016
3017 r = unit_freezer_freeze(&f);
3018 if (r < 0)
3019 return r;
3020
3021 *ret = TAKE_STRUCT(f);
3022 return 0;
3023 }
3024
3025 void unit_freezer_done_thaw(UnitFreezer *f) {
3026 assert(f);
3027
3028 if (!f->name)
3029 return;
3030
3031 (void) unit_freezer_thaw(f);
3032 unit_freezer_done(f);
3033 }