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