]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
cryptsetup: mention correct action in log message
[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 "PassFileDescriptorsToExec",
2454 "PassSecurity",
2455 "PassPacketInfo",
2456 "ReusePort",
2457 "RemoveOnStop",
2458 "SELinuxContextFromNet"))
2459 return bus_append_parse_boolean(m, field, eq);
2460
2461 if (STR_IN_SET(field, "Priority",
2462 "IPTTL",
2463 "Mark"))
2464 return bus_append_safe_atoi(m, field, eq);
2465
2466 if (streq(field, "IPTOS"))
2467 return bus_append_ip_tos_from_string(m, field, eq);
2468
2469 if (STR_IN_SET(field, "Backlog",
2470 "MaxConnections",
2471 "MaxConnectionsPerSource",
2472 "KeepAliveProbes",
2473 "TriggerLimitBurst",
2474 "PollLimitBurst"))
2475 return bus_append_safe_atou(m, field, eq);
2476
2477 if (STR_IN_SET(field, "SocketMode",
2478 "DirectoryMode"))
2479 return bus_append_parse_mode(m, field, eq);
2480
2481 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2482 "MessageQueueMessageSize"))
2483 return bus_append_safe_atoi64(m, field, eq);
2484
2485 if (STR_IN_SET(field, "TimeoutSec",
2486 "KeepAliveTimeSec",
2487 "KeepAliveIntervalSec",
2488 "DeferAcceptSec",
2489 "TriggerLimitIntervalSec",
2490 "PollLimitIntervalSec"))
2491 return bus_append_parse_sec_rename(m, field, eq);
2492
2493 if (STR_IN_SET(field, "ReceiveBuffer",
2494 "SendBuffer",
2495 "PipeSize"))
2496 return bus_append_parse_size(m, field, eq, 1024);
2497
2498 if (STR_IN_SET(field, "ExecStartPre",
2499 "ExecStartPost",
2500 "ExecReload",
2501 "ExecStopPost"))
2502 return bus_append_exec_command(m, field, eq);
2503
2504 if (STR_IN_SET(field, "SmackLabel",
2505 "SmackLabelIPIn",
2506 "SmackLabelIPOut",
2507 "TCPCongestion",
2508 "BindToDevice",
2509 "BindIPv6Only",
2510 "FileDescriptorName",
2511 "SocketUser",
2512 "SocketGroup",
2513 "Timestamping"))
2514 return bus_append_string(m, field, eq);
2515
2516 if (streq(field, "Symlinks"))
2517 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
2518
2519 if (streq(field, "SocketProtocol"))
2520 return bus_append_parse_ip_protocol(m, field, eq);
2521
2522 if (STR_IN_SET(field, "ListenStream",
2523 "ListenDatagram",
2524 "ListenSequentialPacket",
2525 "ListenNetlink",
2526 "ListenSpecial",
2527 "ListenMessageQueue",
2528 "ListenFIFO",
2529 "ListenUSBFunction")) {
2530 if (isempty(eq))
2531 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2532 else
2533 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
2534 if (r < 0)
2535 return bus_log_create_error(r);
2536
2537 return 1;
2538 }
2539
2540 return 0;
2541 }
2542 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
2543 int r;
2544
2545 if (STR_IN_SET(field, "WakeSystem",
2546 "RemainAfterElapse",
2547 "Persistent",
2548 "OnTimezoneChange",
2549 "OnClockChange",
2550 "FixedRandomDelay"))
2551 return bus_append_parse_boolean(m, field, eq);
2552
2553 if (STR_IN_SET(field, "AccuracySec",
2554 "RandomizedDelaySec"))
2555 return bus_append_parse_sec_rename(m, field, eq);
2556
2557 if (STR_IN_SET(field, "OnActiveSec",
2558 "OnBootSec",
2559 "OnStartupSec",
2560 "OnUnitActiveSec",
2561 "OnUnitInactiveSec")) {
2562 if (isempty(eq))
2563 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2564 else {
2565 usec_t t;
2566 r = parse_sec(eq, &t);
2567 if (r < 0)
2568 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
2569
2570 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2571 }
2572 if (r < 0)
2573 return bus_log_create_error(r);
2574
2575 return 1;
2576 }
2577
2578 if (streq(field, "OnCalendar")) {
2579 if (isempty(eq))
2580 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2581 else
2582 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2583 if (r < 0)
2584 return bus_log_create_error(r);
2585
2586 return 1;
2587 }
2588
2589 return 0;
2590 }
2591
2592 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
2593 ConditionType t = _CONDITION_TYPE_INVALID;
2594 bool is_condition = false;
2595 int r;
2596
2597 if (STR_IN_SET(field, "Description",
2598 "SourcePath",
2599 "OnFailureJobMode",
2600 "JobTimeoutAction",
2601 "JobTimeoutRebootArgument",
2602 "StartLimitAction",
2603 "FailureAction",
2604 "SuccessAction",
2605 "RebootArgument",
2606 "CollectMode"))
2607 return bus_append_string(m, field, eq);
2608
2609 if (STR_IN_SET(field, "StopWhenUnneeded",
2610 "RefuseManualStart",
2611 "RefuseManualStop",
2612 "AllowIsolate",
2613 "IgnoreOnIsolate",
2614 "SurviveFinalKillSignal",
2615 "DefaultDependencies"))
2616 return bus_append_parse_boolean(m, field, eq);
2617
2618 if (STR_IN_SET(field, "JobTimeoutSec",
2619 "JobRunningTimeoutSec",
2620 "StartLimitIntervalSec"))
2621 return bus_append_parse_sec_rename(m, field, eq);
2622
2623 if (streq(field, "StartLimitBurst"))
2624 return bus_append_safe_atou(m, field, eq);
2625
2626 if (STR_IN_SET(field, "SuccessActionExitStatus",
2627 "FailureActionExitStatus")) {
2628 if (isempty(eq))
2629 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2630 else {
2631 uint8_t u;
2632
2633 r = safe_atou8(eq, &u);
2634 if (r < 0)
2635 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2636
2637 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2638 }
2639 if (r < 0)
2640 return bus_log_create_error(r);
2641
2642 return 1;
2643 }
2644
2645 if (unit_dependency_from_string(field) >= 0 ||
2646 STR_IN_SET(field, "Documentation",
2647 "RequiresMountsFor",
2648 "WantsMountsFor",
2649 "Markers"))
2650 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
2651
2652 t = condition_type_from_string(field);
2653 if (t >= 0)
2654 is_condition = true;
2655 else
2656 t = assert_type_from_string(field);
2657 if (t >= 0) {
2658 if (isempty(eq))
2659 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2660 else {
2661 const char *p = eq;
2662 int trigger, negate;
2663
2664 trigger = *p == '|';
2665 if (trigger)
2666 p++;
2667
2668 negate = *p == '!';
2669 if (negate)
2670 p++;
2671
2672 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2673 field, trigger, negate, p);
2674 }
2675 if (r < 0)
2676 return bus_log_create_error(r);
2677
2678 return 1;
2679 }
2680
2681 return 0;
2682 }
2683
2684 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2685 const char *eq, *field;
2686 int r;
2687
2688 assert(m);
2689 assert(assignment);
2690
2691 eq = strchr(assignment, '=');
2692 if (!eq)
2693 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2694 "Not an assignment: %s", assignment);
2695
2696 field = strndupa_safe(assignment, eq - assignment);
2697 eq++;
2698
2699 switch (t) {
2700 case UNIT_SERVICE:
2701 r = bus_append_cgroup_property(m, field, eq);
2702 if (r != 0)
2703 return r;
2704
2705 r = bus_append_execute_property(m, field, eq);
2706 if (r != 0)
2707 return r;
2708
2709 r = bus_append_kill_property(m, field, eq);
2710 if (r != 0)
2711 return r;
2712
2713 r = bus_append_service_property(m, field, eq);
2714 if (r != 0)
2715 return r;
2716 break;
2717
2718 case UNIT_SOCKET:
2719 r = bus_append_cgroup_property(m, field, eq);
2720 if (r != 0)
2721 return r;
2722
2723 r = bus_append_execute_property(m, field, eq);
2724 if (r != 0)
2725 return r;
2726
2727 r = bus_append_kill_property(m, field, eq);
2728 if (r != 0)
2729 return r;
2730
2731 r = bus_append_socket_property(m, field, eq);
2732 if (r != 0)
2733 return r;
2734 break;
2735
2736 case UNIT_TIMER:
2737 r = bus_append_timer_property(m, field, eq);
2738 if (r != 0)
2739 return r;
2740 break;
2741
2742 case UNIT_PATH:
2743 r = bus_append_path_property(m, field, eq);
2744 if (r != 0)
2745 return r;
2746 break;
2747
2748 case UNIT_SLICE:
2749 r = bus_append_cgroup_property(m, field, eq);
2750 if (r != 0)
2751 return r;
2752 break;
2753
2754 case UNIT_SCOPE:
2755 r = bus_append_cgroup_property(m, field, eq);
2756 if (r != 0)
2757 return r;
2758
2759 r = bus_append_kill_property(m, field, eq);
2760 if (r != 0)
2761 return r;
2762
2763 r = bus_append_scope_property(m, field, eq);
2764 if (r != 0)
2765 return r;
2766 break;
2767
2768 case UNIT_MOUNT:
2769 r = bus_append_cgroup_property(m, field, eq);
2770 if (r != 0)
2771 return r;
2772
2773 r = bus_append_execute_property(m, field, eq);
2774 if (r != 0)
2775 return r;
2776
2777 r = bus_append_kill_property(m, field, eq);
2778 if (r != 0)
2779 return r;
2780
2781 r = bus_append_mount_property(m, field, eq);
2782 if (r != 0)
2783 return r;
2784
2785 break;
2786
2787 case UNIT_AUTOMOUNT:
2788 r = bus_append_automount_property(m, field, eq);
2789 if (r != 0)
2790 return r;
2791
2792 break;
2793
2794 case UNIT_TARGET:
2795 case UNIT_DEVICE:
2796 case UNIT_SWAP:
2797 break;
2798
2799 default:
2800 assert_not_reached();
2801 }
2802
2803 r = bus_append_unit_property(m, field, eq);
2804 if (r != 0)
2805 return r;
2806
2807 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2808 "Unknown assignment: %s", assignment);
2809 }
2810
2811 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
2812 int r;
2813
2814 assert(m);
2815
2816 STRV_FOREACH(i, l) {
2817 r = bus_append_unit_property_assignment(m, t, *i);
2818 if (r < 0)
2819 return r;
2820 }
2821
2822 return 0;
2823 }
2824
2825 int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
2826 assert(m);
2827
2828 if (!pidref_is_set(pidref))
2829 return -ESRCH;
2830
2831 if (pidref->fd >= 0 && allow_pidfd)
2832 return sd_bus_message_append(
2833 m, "(sv)",
2834 "PIDFDs", "ah", 1, pidref->fd);
2835
2836 return sd_bus_message_append(
2837 m, "(sv)",
2838 "PIDs", "au", 1, pidref->pid);
2839 }
2840
2841 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
2842 const char *type, *path, *source;
2843 InstallChange *changes = NULL;
2844 size_t n_changes = 0;
2845 int r;
2846
2847 CLEANUP_ARRAY(changes, n_changes, install_changes_free);
2848
2849 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2850 if (r < 0)
2851 return bus_log_parse_error(r);
2852
2853 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2854 InstallChangeType t;
2855
2856 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2857 * negative. */
2858 t = install_change_type_from_string(type);
2859 if (t < 0) {
2860 log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2861 type, path);
2862 continue;
2863 }
2864
2865 r = install_changes_add(&changes, &n_changes, t, path, source);
2866 if (r < 0)
2867 return r;
2868 }
2869 if (r < 0)
2870 return bus_log_parse_error(r);
2871
2872 r = sd_bus_message_exit_container(m);
2873 if (r < 0)
2874 return bus_log_parse_error(r);
2875
2876 install_changes_dump(0, NULL, changes, n_changes, quiet);
2877
2878 return 0;
2879 }
2880
2881 int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2882 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2883 _cleanup_free_ char *path = NULL;
2884 int r;
2885
2886 path = unit_dbus_path_from_name(name);
2887 if (!path)
2888 return log_oom();
2889
2890 /* This function warns on its own, because otherwise it'd be awkward to pass
2891 * the dbus error message around. */
2892
2893 r = sd_bus_get_property_string(
2894 bus,
2895 "org.freedesktop.systemd1",
2896 path,
2897 "org.freedesktop.systemd1.Unit",
2898 "LoadState",
2899 &error,
2900 load_state);
2901 if (r < 0)
2902 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2903
2904 return 0;
2905 }
2906
2907 int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2908 int r;
2909
2910 /* First, order by machine */
2911 r = strcasecmp_ptr(a->machine, b->machine);
2912 if (r != 0)
2913 return r;
2914
2915 /* Second, order by unit type */
2916 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2917 if (r != 0)
2918 return r;
2919
2920 /* Third, order by name */
2921 return strcasecmp(a->id, b->id);
2922 }
2923
2924 int bus_service_manager_reload(sd_bus *bus) {
2925 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2926 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2927 int r;
2928
2929 assert(bus);
2930
2931 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
2932 if (r < 0)
2933 return bus_log_create_error(r);
2934
2935 /* Reloading the daemon may take long, hence set a longer timeout here */
2936 r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
2937 if (r < 0)
2938 return log_error_errno(r, "Failed to reload service manager: %s", bus_error_message(&error, r));
2939
2940 return 0;
2941 }
2942
2943 /* Wait for 1.5 seconds at maximum for freeze operation */
2944 #define FREEZE_BUS_CALL_TIMEOUT (1500 * USEC_PER_MSEC)
2945
2946 int unit_freezer_new(const char *name, UnitFreezer *ret) {
2947 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2948 _cleanup_free_ char *namedup = NULL;
2949 int r;
2950
2951 assert(name);
2952 assert(ret);
2953
2954 namedup = strdup(name);
2955 if (!namedup)
2956 return log_oom_debug();
2957
2958 r = bus_connect_system_systemd(&bus);
2959 if (r < 0)
2960 return log_debug_errno(r, "Failed to open connection to systemd: %m");
2961
2962 (void) sd_bus_set_method_call_timeout(bus, FREEZE_BUS_CALL_TIMEOUT);
2963
2964 *ret = (UnitFreezer) {
2965 .name = TAKE_PTR(namedup),
2966 .bus = TAKE_PTR(bus),
2967 };
2968 return 0;
2969 }
2970
2971 void unit_freezer_done(UnitFreezer *f) {
2972 assert(f);
2973
2974 f->name = mfree(f->name);
2975 f->bus = sd_bus_flush_close_unref(f->bus);
2976 }
2977
2978 static int unit_freezer_action(UnitFreezer *f, bool freeze) {
2979 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2980 int r;
2981
2982 assert(f);
2983 assert(f->name);
2984 assert(f->bus);
2985
2986 r = bus_call_method(f->bus, bus_systemd_mgr,
2987 freeze ? "FreezeUnit" : "ThawUnit",
2988 &error,
2989 /* reply = */ NULL,
2990 "s",
2991 f->name);
2992 if (r < 0)
2993 return log_debug_errno(r, "Failed to %s unit %s: %s",
2994 freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
2995
2996 return 0;
2997 }
2998
2999 int unit_freezer_freeze(UnitFreezer *f) {
3000 return unit_freezer_action(f, true);
3001 }
3002
3003 int unit_freezer_thaw(UnitFreezer *f) {
3004 return unit_freezer_action(f, false);
3005 }
3006
3007 int unit_freezer_new_freeze(const char *name, UnitFreezer *ret) {
3008 _cleanup_(unit_freezer_done) UnitFreezer f = {};
3009 int r;
3010
3011 assert(name);
3012 assert(ret);
3013
3014 r = unit_freezer_new(name, &f);
3015 if (r < 0)
3016 return r;
3017
3018 r = unit_freezer_freeze(&f);
3019 if (r < 0)
3020 return r;
3021
3022 *ret = TAKE_STRUCT(f);
3023 return 0;
3024 }
3025
3026 void unit_freezer_done_thaw(UnitFreezer *f) {
3027 assert(f);
3028
3029 if (!f->name)
3030 return;
3031
3032 (void) unit_freezer_thaw(f);
3033 unit_freezer_done(f);
3034 }