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