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