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