]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
Merge pull request #16059 from keszybz/resolve-single-label-names
[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 (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 } else if (isempty(eq) && STR_IN_SET(field, "DefaultMemoryLow",
498 "DefaultMemoryMin",
499 "MemoryLow",
500 "MemoryMin")) {
501 /* We can't use CGROUP_LIMIT_MIN nor CGROUP_LIMIT_MAX to convey the empty assignment
502 * so marshall specially as a boolean. */
503 r = sd_bus_message_append(m, "(sv)", field, "b", 0);
504 if (r < 0)
505 return bus_log_create_error(r);
506 return 1;
507 } else if (isempty(eq)) {
508 r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
509 if (r < 0)
510 return bus_log_create_error(r);
511 return 1;
512 }
513
514 r = parse_permille(eq);
515 if (r >= 0) {
516 char *n;
517
518 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
519 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
520 * size can be determined server-side. */
521
522 n = strjoina(field, "Scale");
523 r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
524 if (r < 0)
525 return bus_log_create_error(r);
526
527 return 1;
528 }
529
530 if (streq(field, "TasksMax"))
531 return bus_append_safe_atou64(m, field, eq);
532
533 return bus_append_parse_size(m, field, eq, 1024);
534 }
535
536 if (streq(field, "CPUQuota")) {
537 if (isempty(eq))
538 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
539 else {
540 r = parse_permille_unbounded(eq);
541 if (r == 0)
542 return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
543 "CPU quota too small.");
544 if (r < 0)
545 return log_error_errno(r, "CPU quota '%s' invalid.", eq);
546
547 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U));
548 }
549
550 if (r < 0)
551 return bus_log_create_error(r);
552
553 return 1;
554 }
555
556 if (streq(field, "CPUQuotaPeriodSec")) {
557 usec_t u = USEC_INFINITY;
558
559 r = parse_sec_def_infinity(eq, &u);
560 if (r < 0)
561 return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
562
563 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
564 if (r < 0)
565 return bus_log_create_error(r);
566
567 return 1;
568 }
569
570 if (streq(field, "DeviceAllow")) {
571 if (isempty(eq))
572 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
573 else {
574 const char *path = eq, *rwm = NULL, *e;
575
576 e = strchr(eq, ' ');
577 if (e) {
578 path = strndupa(eq, e - eq);
579 rwm = e+1;
580 }
581
582 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
583 }
584
585 if (r < 0)
586 return bus_log_create_error(r);
587
588 return 1;
589 }
590
591 if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
592 if (isempty(eq))
593 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
594 else {
595 const char *path, *bandwidth, *e;
596 uint64_t bytes;
597
598 e = strchr(eq, ' ');
599 if (!e)
600 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
601 "Failed to parse %s value %s.",
602 field, eq);
603
604 path = strndupa(eq, e - eq);
605 bandwidth = e+1;
606
607 if (streq(bandwidth, "infinity"))
608 bytes = CGROUP_LIMIT_MAX;
609 else {
610 r = parse_size(bandwidth, 1000, &bytes);
611 if (r < 0)
612 return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
613 }
614
615 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
616 }
617
618 if (r < 0)
619 return bus_log_create_error(r);
620
621 return 1;
622 }
623
624 if (STR_IN_SET(field, "IODeviceWeight",
625 "BlockIODeviceWeight")) {
626 if (isempty(eq))
627 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
628 else {
629 const char *path, *weight, *e;
630 uint64_t u;
631
632 e = strchr(eq, ' ');
633 if (!e)
634 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
635 "Failed to parse %s value %s.",
636 field, eq);
637
638 path = strndupa(eq, e - eq);
639 weight = e+1;
640
641 r = safe_atou64(weight, &u);
642 if (r < 0)
643 return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
644
645 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
646 }
647
648 if (r < 0)
649 return bus_log_create_error(r);
650
651 return 1;
652 }
653
654 if (streq(field, "IODeviceLatencyTargetSec")) {
655 const char *field_usec = "IODeviceLatencyTargetUSec";
656
657 if (isempty(eq))
658 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
659 else {
660 const char *path, *target, *e;
661 usec_t usec;
662
663 e = strchr(eq, ' ');
664 if (!e)
665 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
666 "Failed to parse %s value %s.",
667 field, eq);
668
669 path = strndupa(eq, e - eq);
670 target = e+1;
671
672 r = parse_sec(target, &usec);
673 if (r < 0)
674 return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
675
676 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
677 }
678
679 if (r < 0)
680 return bus_log_create_error(r);
681
682 return 1;
683 }
684
685 if (STR_IN_SET(field, "IPAddressAllow",
686 "IPAddressDeny")) {
687 unsigned char prefixlen;
688 union in_addr_union prefix = {};
689 int family;
690
691 if (isempty(eq)) {
692 r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
693 if (r < 0)
694 return bus_log_create_error(r);
695
696 return 1;
697 }
698
699 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
700 if (r < 0)
701 return bus_log_create_error(r);
702
703 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
704 if (r < 0)
705 return bus_log_create_error(r);
706
707 r = sd_bus_message_open_container(m, 'v', "a(iayu)");
708 if (r < 0)
709 return bus_log_create_error(r);
710
711 r = sd_bus_message_open_container(m, 'a', "(iayu)");
712 if (r < 0)
713 return bus_log_create_error(r);
714
715 if (streq(eq, "any")) {
716 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
717
718 r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
719 if (r < 0)
720 return bus_log_create_error(r);
721
722 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
723 if (r < 0)
724 return bus_log_create_error(r);
725
726 } else if (is_localhost(eq)) {
727 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
728
729 prefix.in.s_addr = htobe32(0x7f000000);
730 r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
731 if (r < 0)
732 return bus_log_create_error(r);
733
734 prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
735 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
736 if (r < 0)
737 return r;
738
739 } else if (streq(eq, "link-local")) {
740 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
741
742 prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
743 r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
744 if (r < 0)
745 return bus_log_create_error(r);
746
747 prefix.in6 = (struct in6_addr) {
748 .s6_addr32[0] = htobe32(0xfe800000)
749 };
750 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
751 if (r < 0)
752 return bus_log_create_error(r);
753
754 } else if (streq(eq, "multicast")) {
755 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
756
757 prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
758 r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
759 if (r < 0)
760 return bus_log_create_error(r);
761
762 prefix.in6 = (struct in6_addr) {
763 .s6_addr32[0] = htobe32(0xff000000)
764 };
765 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
766 if (r < 0)
767 return bus_log_create_error(r);
768
769 } else {
770 for (;;) {
771 _cleanup_free_ char *word = NULL;
772
773 r = extract_first_word(&eq, &word, NULL, 0);
774 if (r == 0)
775 break;
776 if (r == -ENOMEM)
777 return log_oom();
778 if (r < 0)
779 return log_error_errno(r, "Failed to parse %s: %s", field, eq);
780
781 r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
782 if (r < 0)
783 return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
784
785 r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
786 if (r < 0)
787 return bus_log_create_error(r);
788 }
789 }
790
791 r = sd_bus_message_close_container(m);
792 if (r < 0)
793 return bus_log_create_error(r);
794
795 r = sd_bus_message_close_container(m);
796 if (r < 0)
797 return bus_log_create_error(r);
798
799 r = sd_bus_message_close_container(m);
800 if (r < 0)
801 return bus_log_create_error(r);
802
803 return 1;
804 }
805
806 if (STR_IN_SET(field, "IPIngressFilterPath",
807 "IPEgressFilterPath")) {
808 if (isempty(eq))
809 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
810 else
811 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
812
813 if (r < 0)
814 return bus_log_create_error(r);
815
816 return 1;
817 }
818
819 return 0;
820 }
821
822 static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
823 if (streq(field, "Where"))
824 return bus_append_string(m, field, eq);
825
826 if (streq(field, "DirectoryMode"))
827 return bus_append_parse_mode(m, field, eq);
828
829 if (streq(field, "TimeoutIdleSec"))
830 return bus_append_parse_sec_rename(m, field, eq);
831
832 return 0;
833 }
834
835 static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
836 const char *suffix;
837 int r;
838
839 if (STR_IN_SET(field, "User",
840 "Group",
841 "UtmpIdentifier",
842 "UtmpMode",
843 "PAMName",
844 "TTYPath",
845 "WorkingDirectory",
846 "RootDirectory",
847 "SyslogIdentifier",
848 "ProtectSystem",
849 "ProtectHome",
850 "SELinuxContext",
851 "RootImage",
852 "RuntimeDirectoryPreserve",
853 "Personality",
854 "KeyringMode",
855 "NetworkNamespacePath",
856 "LogNamespace"))
857 return bus_append_string(m, field, eq);
858
859 if (STR_IN_SET(field, "IgnoreSIGPIPE",
860 "TTYVHangup",
861 "TTYReset",
862 "TTYVTDisallocate",
863 "PrivateTmp",
864 "PrivateDevices",
865 "PrivateNetwork",
866 "PrivateUsers",
867 "PrivateMounts",
868 "NoNewPrivileges",
869 "SyslogLevelPrefix",
870 "MemoryDenyWriteExecute",
871 "RestrictRealtime",
872 "DynamicUser",
873 "RemoveIPC",
874 "ProtectKernelTunables",
875 "ProtectKernelModules",
876 "ProtectKernelLogs",
877 "ProtectClock",
878 "ProtectControlGroups",
879 "MountAPIVFS",
880 "CPUSchedulingResetOnFork",
881 "LockPersonality",
882 "ProtectHostname",
883 "RestrictSUIDSGID"))
884 return bus_append_parse_boolean(m, field, eq);
885
886 if (STR_IN_SET(field, "ReadWriteDirectories",
887 "ReadOnlyDirectories",
888 "InaccessibleDirectories",
889 "ReadWritePaths",
890 "ReadOnlyPaths",
891 "InaccessiblePaths",
892 "RuntimeDirectory",
893 "StateDirectory",
894 "CacheDirectory",
895 "LogsDirectory",
896 "ConfigurationDirectory",
897 "SupplementaryGroups",
898 "SystemCallArchitectures"))
899 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
900
901 if (STR_IN_SET(field, "SyslogLevel",
902 "LogLevelMax"))
903 return bus_append_log_level_from_string(m, field, eq);
904
905 if (streq(field, "SyslogFacility"))
906 return bus_append_log_facility_unshifted_from_string(m, field, eq);
907
908 if (streq(field, "SecureBits"))
909 return bus_append_secure_bits_from_string(m, field, eq);
910
911 if (streq(field, "CPUSchedulingPolicy"))
912 return bus_append_sched_policy_from_string(m, field, eq);
913
914 if (STR_IN_SET(field, "CPUSchedulingPriority",
915 "OOMScoreAdjust"))
916 return bus_append_safe_atoi(m, field, eq);
917
918 if (streq(field, "CoredumpFilter"))
919 return bus_append_coredump_filter_mask_from_string(m, field, eq);
920
921 if (streq(field, "Nice"))
922 return bus_append_parse_nice(m, field, eq);
923
924 if (streq(field, "SystemCallErrorNumber"))
925 return bus_append_parse_errno(m, field, eq);
926
927 if (streq(field, "IOSchedulingClass"))
928 return bus_append_ioprio_class_from_string(m, field, eq);
929
930 if (streq(field, "IOSchedulingPriority"))
931 return bus_append_ioprio_parse_priority(m, field, eq);
932
933 if (STR_IN_SET(field, "RuntimeDirectoryMode",
934 "StateDirectoryMode",
935 "CacheDirectoryMode",
936 "LogsDirectoryMode",
937 "ConfigurationDirectoryMode",
938 "UMask"))
939 return bus_append_parse_mode(m, field, eq);
940
941 if (streq(field, "TimerSlackNSec"))
942 return bus_append_parse_nsec(m, field, eq);
943
944 if (streq(field, "LogRateLimitIntervalSec"))
945 return bus_append_parse_sec_rename(m, field, eq);
946
947 if (streq(field, "LogRateLimitBurst"))
948 return bus_append_safe_atou(m, field, eq);
949
950 if (streq(field, "MountFlags"))
951 return bus_append_mount_propagation_flags_from_string(m, field, eq);
952
953 if (STR_IN_SET(field, "Environment",
954 "UnsetEnvironment",
955 "PassEnvironment"))
956 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
957
958 if (streq(field, "EnvironmentFile")) {
959 if (isempty(eq))
960 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
961 else
962 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
963 eq[0] == '-' ? eq + 1 : eq,
964 eq[0] == '-');
965 if (r < 0)
966 return bus_log_create_error(r);
967
968 return 1;
969 }
970
971 if (streq(field, "LogExtraFields")) {
972 r = sd_bus_message_open_container(m, 'r', "sv");
973 if (r < 0)
974 return bus_log_create_error(r);
975
976 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
977 if (r < 0)
978 return bus_log_create_error(r);
979
980 r = sd_bus_message_open_container(m, 'v', "aay");
981 if (r < 0)
982 return bus_log_create_error(r);
983
984 r = sd_bus_message_open_container(m, 'a', "ay");
985 if (r < 0)
986 return bus_log_create_error(r);
987
988 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
989 if (r < 0)
990 return bus_log_create_error(r);
991
992 r = sd_bus_message_close_container(m);
993 if (r < 0)
994 return bus_log_create_error(r);
995
996 r = sd_bus_message_close_container(m);
997 if (r < 0)
998 return bus_log_create_error(r);
999
1000 r = sd_bus_message_close_container(m);
1001 if (r < 0)
1002 return bus_log_create_error(r);
1003
1004 return 1;
1005 }
1006
1007 if (STR_IN_SET(field, "StandardInput",
1008 "StandardOutput",
1009 "StandardError")) {
1010 const char *n, *appended;
1011
1012 if ((n = startswith(eq, "fd:"))) {
1013 appended = strjoina(field, "FileDescriptorName");
1014 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1015 } else if ((n = startswith(eq, "file:"))) {
1016 appended = strjoina(field, "File");
1017 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1018 } else if ((n = startswith(eq, "append:"))) {
1019 appended = strjoina(field, "FileToAppend");
1020 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1021 } else
1022 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
1023 if (r < 0)
1024 return bus_log_create_error(r);
1025
1026 return 1;
1027 }
1028
1029 if (streq(field, "StandardInputText")) {
1030 _cleanup_free_ char *unescaped = NULL;
1031
1032 r = cunescape(eq, 0, &unescaped);
1033 if (r < 0)
1034 return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
1035
1036 if (!strextend(&unescaped, "\n", NULL))
1037 return log_oom();
1038
1039 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
1040 * interface anyway */
1041
1042 return bus_append_byte_array(m, field, unescaped, strlen(unescaped));
1043 }
1044
1045 if (streq(field, "StandardInputData")) {
1046 _cleanup_free_ void *decoded = NULL;
1047 size_t sz;
1048
1049 r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
1050 if (r < 0)
1051 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
1052
1053 return bus_append_byte_array(m, field, decoded, sz);
1054 }
1055
1056 if ((suffix = startswith(field, "Limit"))) {
1057 int rl;
1058
1059 rl = rlimit_from_string(suffix);
1060 if (rl >= 0) {
1061 const char *sn;
1062 struct rlimit l;
1063
1064 r = rlimit_parse(rl, eq, &l);
1065 if (r < 0)
1066 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
1067
1068 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
1069 if (r < 0)
1070 return bus_log_create_error(r);
1071
1072 sn = strjoina(field, "Soft");
1073 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
1074 if (r < 0)
1075 return bus_log_create_error(r);
1076
1077 return 1;
1078 }
1079 }
1080
1081 if (STR_IN_SET(field, "AppArmorProfile",
1082 "SmackProcessLabel")) {
1083 int ignore = 0;
1084 const char *s = eq;
1085
1086 if (eq[0] == '-') {
1087 ignore = 1;
1088 s = eq + 1;
1089 }
1090
1091 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
1092 if (r < 0)
1093 return bus_log_create_error(r);
1094
1095 return 1;
1096 }
1097
1098 if (STR_IN_SET(field, "CapabilityBoundingSet",
1099 "AmbientCapabilities")) {
1100 uint64_t sum = 0;
1101 bool invert = false;
1102 const char *p = eq;
1103
1104 if (*p == '~') {
1105 invert = true;
1106 p++;
1107 }
1108
1109 r = capability_set_from_string(p, &sum);
1110 if (r < 0)
1111 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
1112
1113 sum = invert ? ~sum : sum;
1114
1115 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
1116 if (r < 0)
1117 return bus_log_create_error(r);
1118
1119 return 1;
1120 }
1121
1122 if (streq(field, "CPUAffinity")) {
1123 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
1124 _cleanup_free_ uint8_t *array = NULL;
1125 size_t allocated;
1126
1127 if (eq && streq(eq, "numa")) {
1128 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1129 if (r < 0)
1130 return bus_log_create_error(r);
1131 return r;
1132 }
1133
1134 r = parse_cpu_set(eq, &cpuset);
1135 if (r < 0)
1136 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1137
1138 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1139 if (r < 0)
1140 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1141
1142 return bus_append_byte_array(m, field, array, allocated);
1143 }
1144
1145 if (streq(field, "NUMAPolicy")) {
1146 r = mpol_from_string(eq);
1147 if (r < 0)
1148 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1149
1150 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1151 if (r < 0)
1152 return bus_log_create_error(r);
1153
1154 return 1;
1155 }
1156
1157 if (streq(field, "NUMAMask")) {
1158 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1159 _cleanup_free_ uint8_t *array = NULL;
1160 size_t allocated;
1161
1162 r = parse_cpu_set(eq, &nodes);
1163 if (r < 0)
1164 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1165
1166 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1167 if (r < 0)
1168 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1169
1170 return bus_append_byte_array(m, field, array, allocated);
1171 }
1172
1173 if (STR_IN_SET(field, "RestrictAddressFamilies",
1174 "SystemCallFilter")) {
1175 int whitelist = 1;
1176 const char *p = eq;
1177
1178 if (*p == '~') {
1179 whitelist = 0;
1180 p++;
1181 }
1182
1183 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1184 if (r < 0)
1185 return bus_log_create_error(r);
1186
1187 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1188 if (r < 0)
1189 return bus_log_create_error(r);
1190
1191 r = sd_bus_message_open_container(m, 'v', "(bas)");
1192 if (r < 0)
1193 return bus_log_create_error(r);
1194
1195 r = sd_bus_message_open_container(m, 'r', "bas");
1196 if (r < 0)
1197 return bus_log_create_error(r);
1198
1199 r = sd_bus_message_append_basic(m, 'b', &whitelist);
1200 if (r < 0)
1201 return bus_log_create_error(r);
1202
1203 r = sd_bus_message_open_container(m, 'a', "s");
1204 if (r < 0)
1205 return bus_log_create_error(r);
1206
1207 for (;;) {
1208 _cleanup_free_ char *word = NULL;
1209
1210 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1211 if (r == 0)
1212 break;
1213 if (r == -ENOMEM)
1214 return log_oom();
1215 if (r < 0)
1216 return log_error_errno(r, "Invalid syntax: %s", eq);
1217
1218 r = sd_bus_message_append_basic(m, 's', word);
1219 if (r < 0)
1220 return bus_log_create_error(r);
1221 }
1222
1223 r = sd_bus_message_close_container(m);
1224 if (r < 0)
1225 return bus_log_create_error(r);
1226
1227 r = sd_bus_message_close_container(m);
1228 if (r < 0)
1229 return bus_log_create_error(r);
1230
1231 r = sd_bus_message_close_container(m);
1232 if (r < 0)
1233 return bus_log_create_error(r);
1234
1235 r = sd_bus_message_close_container(m);
1236 if (r < 0)
1237 return bus_log_create_error(r);
1238
1239 return 1;
1240 }
1241
1242 if (streq(field, "RestrictNamespaces")) {
1243 bool invert = false;
1244 unsigned long flags;
1245
1246 r = parse_boolean(eq);
1247 if (r > 0)
1248 flags = 0;
1249 else if (r == 0)
1250 flags = NAMESPACE_FLAGS_ALL;
1251 else {
1252 if (eq[0] == '~') {
1253 invert = true;
1254 eq++;
1255 }
1256
1257 r = namespace_flags_from_string(eq, &flags);
1258 if (r < 0)
1259 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1260 }
1261
1262 if (invert)
1263 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1264
1265 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1266 if (r < 0)
1267 return bus_log_create_error(r);
1268
1269 return 1;
1270 }
1271
1272 if (STR_IN_SET(field, "BindPaths",
1273 "BindReadOnlyPaths")) {
1274 const char *p = eq;
1275
1276 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1277 if (r < 0)
1278 return bus_log_create_error(r);
1279
1280 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1281 if (r < 0)
1282 return bus_log_create_error(r);
1283
1284 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1285 if (r < 0)
1286 return bus_log_create_error(r);
1287
1288 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1289 if (r < 0)
1290 return bus_log_create_error(r);
1291
1292 for (;;) {
1293 _cleanup_free_ char *source = NULL, *destination = NULL;
1294 char *s = NULL, *d = NULL;
1295 bool ignore_enoent = false;
1296 uint64_t flags = MS_REC;
1297
1298 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1299 if (r < 0)
1300 return log_error_errno(r, "Failed to parse argument: %m");
1301 if (r == 0)
1302 break;
1303
1304 s = source;
1305 if (s[0] == '-') {
1306 ignore_enoent = true;
1307 s++;
1308 }
1309
1310 if (p && p[-1] == ':') {
1311 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1312 if (r < 0)
1313 return log_error_errno(r, "Failed to parse argument: %m");
1314 if (r == 0)
1315 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1316 "Missing argument after ':': %s",
1317 eq);
1318
1319 d = destination;
1320
1321 if (p && p[-1] == ':') {
1322 _cleanup_free_ char *options = NULL;
1323
1324 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
1325 if (r < 0)
1326 return log_error_errno(r, "Failed to parse argument: %m");
1327
1328 if (isempty(options) || streq(options, "rbind"))
1329 flags = MS_REC;
1330 else if (streq(options, "norbind"))
1331 flags = 0;
1332 else
1333 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1334 "Unknown options: %s",
1335 eq);
1336 }
1337 } else
1338 d = s;
1339
1340 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1341 if (r < 0)
1342 return bus_log_create_error(r);
1343 }
1344
1345 r = sd_bus_message_close_container(m);
1346 if (r < 0)
1347 return bus_log_create_error(r);
1348
1349 r = sd_bus_message_close_container(m);
1350 if (r < 0)
1351 return bus_log_create_error(r);
1352
1353 r = sd_bus_message_close_container(m);
1354 if (r < 0)
1355 return bus_log_create_error(r);
1356
1357 return 1;
1358 }
1359
1360 if (streq(field, "TemporaryFileSystem")) {
1361 const char *p = eq;
1362
1363 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1364 if (r < 0)
1365 return bus_log_create_error(r);
1366
1367 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1368 if (r < 0)
1369 return bus_log_create_error(r);
1370
1371 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1372 if (r < 0)
1373 return bus_log_create_error(r);
1374
1375 r = sd_bus_message_open_container(m, 'a', "(ss)");
1376 if (r < 0)
1377 return bus_log_create_error(r);
1378
1379 for (;;) {
1380 _cleanup_free_ char *word = NULL, *path = NULL;
1381 const char *w;
1382
1383 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1384 if (r < 0)
1385 return log_error_errno(r, "Failed to parse argument: %m");
1386 if (r == 0)
1387 break;
1388
1389 w = word;
1390 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1391 if (r < 0)
1392 return log_error_errno(r, "Failed to parse argument: %m");
1393 if (r == 0)
1394 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1395 "Failed to parse argument: %s",
1396 p);
1397
1398 r = sd_bus_message_append(m, "(ss)", path, w);
1399 if (r < 0)
1400 return bus_log_create_error(r);
1401 }
1402
1403 r = sd_bus_message_close_container(m);
1404 if (r < 0)
1405 return bus_log_create_error(r);
1406
1407 r = sd_bus_message_close_container(m);
1408 if (r < 0)
1409 return bus_log_create_error(r);
1410
1411 r = sd_bus_message_close_container(m);
1412 if (r < 0)
1413 return bus_log_create_error(r);
1414
1415 return 1;
1416 }
1417
1418 return 0;
1419 }
1420
1421 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
1422 if (streq(field, "KillMode"))
1423 return bus_append_string(m, field, eq);
1424
1425 if (STR_IN_SET(field, "SendSIGHUP",
1426 "SendSIGKILL"))
1427 return bus_append_parse_boolean(m, field, eq);
1428
1429 if (STR_IN_SET(field, "KillSignal",
1430 "RestartKillSignal",
1431 "FinalKillSignal",
1432 "WatchdogSignal"))
1433 return bus_append_signal_from_string(m, field, eq);
1434
1435 return 0;
1436 }
1437
1438 static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
1439
1440 if (STR_IN_SET(field, "What",
1441 "Where",
1442 "Options",
1443 "Type"))
1444 return bus_append_string(m, field, eq);
1445
1446 if (streq(field, "TimeoutSec"))
1447 return bus_append_parse_sec_rename(m, field, eq);
1448
1449 if (streq(field, "DirectoryMode"))
1450 return bus_append_parse_mode(m, field, eq);
1451
1452 if (STR_IN_SET(field, "SloppyOptions",
1453 "LazyUnmount",
1454 "ForceUnmount",
1455 "ReadwriteOnly"))
1456 return bus_append_parse_boolean(m, field, eq);
1457
1458 return 0;
1459 }
1460
1461 static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1462 int r;
1463
1464 if (streq(field, "MakeDirectory"))
1465 return bus_append_parse_boolean(m, field, eq);
1466
1467 if (streq(field, "DirectoryMode"))
1468 return bus_append_parse_mode(m, field, eq);
1469
1470 if (STR_IN_SET(field, "PathExists",
1471 "PathExistsGlob",
1472 "PathChanged",
1473 "PathModified",
1474 "DirectoryNotEmpty")) {
1475 if (isempty(eq))
1476 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1477 else
1478 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1479 if (r < 0)
1480 return bus_log_create_error(r);
1481
1482 return 1;
1483 }
1484
1485 return 0;
1486 }
1487
1488 static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
1489 if (streq(field, "RuntimeMaxSec"))
1490 return bus_append_parse_sec_rename(m, field, eq);
1491
1492 if (streq(field, "TimeoutStopSec"))
1493 return bus_append_parse_sec_rename(m, field, eq);
1494
1495 return 0;
1496 }
1497
1498 static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
1499 int r;
1500
1501 if (STR_IN_SET(field, "PIDFile",
1502 "Type",
1503 "Restart",
1504 "BusName",
1505 "NotifyAccess",
1506 "USBFunctionDescriptors",
1507 "USBFunctionStrings",
1508 "OOMPolicy",
1509 "TimeoutStartFailureMode",
1510 "TimeoutStopFailureMode"))
1511 return bus_append_string(m, field, eq);
1512
1513 if (STR_IN_SET(field, "PermissionsStartOnly",
1514 "RootDirectoryStartOnly",
1515 "RemainAfterExit",
1516 "GuessMainPID"))
1517 return bus_append_parse_boolean(m, field, eq);
1518
1519 if (STR_IN_SET(field, "RestartSec",
1520 "TimeoutStartSec",
1521 "TimeoutStopSec",
1522 "TimeoutAbortSec",
1523 "RuntimeMaxSec",
1524 "WatchdogSec"))
1525 return bus_append_parse_sec_rename(m, field, eq);
1526
1527 if (streq(field, "TimeoutSec")) {
1528 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1529 if (r < 0)
1530 return r;
1531
1532 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1533 }
1534
1535 if (streq(field, "FileDescriptorStoreMax"))
1536 return bus_append_safe_atou(m, field, eq);
1537
1538 if (STR_IN_SET(field, "ExecCondition",
1539 "ExecStartPre",
1540 "ExecStart",
1541 "ExecStartPost",
1542 "ExecConditionEx",
1543 "ExecStartPreEx",
1544 "ExecStartEx",
1545 "ExecStartPostEx",
1546 "ExecReload",
1547 "ExecStop",
1548 "ExecStopPost",
1549 "ExecReloadEx",
1550 "ExecStopEx",
1551 "ExecStopPostEx"))
1552 return bus_append_exec_command(m, field, eq);
1553
1554 if (STR_IN_SET(field, "RestartPreventExitStatus",
1555 "RestartForceExitStatus",
1556 "SuccessExitStatus")) {
1557 _cleanup_free_ int *status = NULL, *signal = NULL;
1558 size_t n_status = 0, n_signal = 0;
1559 const char *p;
1560
1561 for (p = eq;;) {
1562 _cleanup_free_ char *word = NULL;
1563
1564 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
1565 if (r == 0)
1566 break;
1567 if (r == -ENOMEM)
1568 return log_oom();
1569 if (r < 0)
1570 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
1571
1572 /* We need to call exit_status_from_string() first, because we want
1573 * to parse numbers as exit statuses, not signals. */
1574
1575 r = exit_status_from_string(word);
1576 if (r >= 0) {
1577 assert(r >= 0 && r < 256);
1578
1579 status = reallocarray(status, n_status + 1, sizeof(int));
1580 if (!status)
1581 return log_oom();
1582
1583 status[n_status++] = r;
1584
1585 } else if ((r = signal_from_string(word)) >= 0) {
1586 signal = reallocarray(signal, n_signal + 1, sizeof(int));
1587 if (!signal)
1588 return log_oom();
1589
1590 signal[n_signal++] = r;
1591
1592 } else
1593 /* original r from exit_status_to_string() */
1594 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
1595 word, field);
1596 }
1597
1598 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1599 if (r < 0)
1600 return bus_log_create_error(r);
1601
1602 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1603 if (r < 0)
1604 return bus_log_create_error(r);
1605
1606 r = sd_bus_message_open_container(m, 'v', "(aiai)");
1607 if (r < 0)
1608 return bus_log_create_error(r);
1609
1610 r = sd_bus_message_open_container(m, 'r', "aiai");
1611 if (r < 0)
1612 return bus_log_create_error(r);
1613
1614 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
1615 if (r < 0)
1616 return bus_log_create_error(r);
1617
1618 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
1619 if (r < 0)
1620 return bus_log_create_error(r);
1621
1622 r = sd_bus_message_close_container(m);
1623 if (r < 0)
1624 return bus_log_create_error(r);
1625
1626 r = sd_bus_message_close_container(m);
1627 if (r < 0)
1628 return bus_log_create_error(r);
1629
1630 r = sd_bus_message_close_container(m);
1631 if (r < 0)
1632 return bus_log_create_error(r);
1633
1634 return 1;
1635 }
1636
1637 return 0;
1638 }
1639
1640 static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1641 int r;
1642
1643 if (STR_IN_SET(field, "Accept",
1644 "Writable",
1645 "KeepAlive",
1646 "NoDelay",
1647 "FreeBind",
1648 "Transparent",
1649 "Broadcast",
1650 "PassCredentials",
1651 "PassSecurity",
1652 "PassPacketInfo",
1653 "ReusePort",
1654 "RemoveOnStop",
1655 "SELinuxContextFromNet"))
1656 return bus_append_parse_boolean(m, field, eq);
1657
1658 if (STR_IN_SET(field, "Priority",
1659 "IPTTL",
1660 "Mark"))
1661 return bus_append_safe_atoi(m, field, eq);
1662
1663 if (streq(field, "IPTOS"))
1664 return bus_append_ip_tos_from_string(m, field, eq);
1665
1666 if (STR_IN_SET(field, "Backlog",
1667 "MaxConnections",
1668 "MaxConnectionsPerSource",
1669 "KeepAliveProbes",
1670 "TriggerLimitBurst"))
1671 return bus_append_safe_atou(m, field, eq);
1672
1673 if (STR_IN_SET(field, "SocketMode",
1674 "DirectoryMode"))
1675 return bus_append_parse_mode(m, field, eq);
1676
1677 if (STR_IN_SET(field, "MessageQueueMaxMessages",
1678 "MessageQueueMessageSize"))
1679 return bus_append_safe_atoi64(m, field, eq);
1680
1681 if (STR_IN_SET(field, "TimeoutSec",
1682 "KeepAliveTimeSec",
1683 "KeepAliveIntervalSec",
1684 "DeferAcceptSec",
1685 "TriggerLimitIntervalSec"))
1686 return bus_append_parse_sec_rename(m, field, eq);
1687
1688 if (STR_IN_SET(field, "ReceiveBuffer",
1689 "SendBuffer",
1690 "PipeSize"))
1691 return bus_append_parse_size(m, field, eq, 1024);
1692
1693 if (STR_IN_SET(field, "ExecStartPre",
1694 "ExecStartPost",
1695 "ExecReload",
1696 "ExecStopPost"))
1697 return bus_append_exec_command(m, field, eq);
1698
1699 if (STR_IN_SET(field, "SmackLabel",
1700 "SmackLabelIPIn",
1701 "SmackLabelIPOut",
1702 "TCPCongestion",
1703 "BindToDevice",
1704 "BindIPv6Only",
1705 "FileDescriptorName",
1706 "SocketUser",
1707 "SocketGroup"))
1708 return bus_append_string(m, field, eq);
1709
1710 if (streq(field, "Symlinks"))
1711 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
1712
1713 if (streq(field, "SocketProtocol"))
1714 return bus_append_parse_ip_protocol(m, field, eq);
1715
1716 if (STR_IN_SET(field, "ListenStream",
1717 "ListenDatagram",
1718 "ListenSequentialPacket",
1719 "ListenNetlink",
1720 "ListenSpecial",
1721 "ListenMessageQueue",
1722 "ListenFIFO",
1723 "ListenUSBFunction")) {
1724 if (isempty(eq))
1725 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
1726 else
1727 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
1728 if (r < 0)
1729 return bus_log_create_error(r);
1730
1731 return 1;
1732 }
1733
1734 return 0;
1735 }
1736 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
1737 int r;
1738
1739 if (STR_IN_SET(field, "WakeSystem",
1740 "RemainAfterElapse",
1741 "Persistent",
1742 "OnTimezoneChange",
1743 "OnClockChange"))
1744 return bus_append_parse_boolean(m, field, eq);
1745
1746 if (STR_IN_SET(field, "AccuracySec",
1747 "RandomizedDelaySec"))
1748 return bus_append_parse_sec_rename(m, field, eq);
1749
1750 if (STR_IN_SET(field, "OnActiveSec",
1751 "OnBootSec",
1752 "OnStartupSec",
1753 "OnUnitActiveSec",
1754 "OnUnitInactiveSec")) {
1755 if (isempty(eq))
1756 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1757 else {
1758 usec_t t;
1759 r = parse_sec(eq, &t);
1760 if (r < 0)
1761 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
1762
1763 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1764 }
1765 if (r < 0)
1766 return bus_log_create_error(r);
1767
1768 return 1;
1769 }
1770
1771 if (streq(field, "OnCalendar")) {
1772 if (isempty(eq))
1773 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1774 else
1775 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1776 if (r < 0)
1777 return bus_log_create_error(r);
1778
1779 return 1;
1780 }
1781
1782 return 0;
1783 }
1784
1785 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
1786 ConditionType t = _CONDITION_TYPE_INVALID;
1787 bool is_condition = false;
1788 int r;
1789
1790 if (STR_IN_SET(field, "Description",
1791 "SourcePath",
1792 "OnFailureJobMode",
1793 "JobTimeoutAction",
1794 "JobTimeoutRebootArgument",
1795 "StartLimitAction",
1796 "FailureAction",
1797 "SuccessAction",
1798 "RebootArgument",
1799 "CollectMode"))
1800 return bus_append_string(m, field, eq);
1801
1802 if (STR_IN_SET(field, "StopWhenUnneeded",
1803 "RefuseManualStart",
1804 "RefuseManualStop",
1805 "AllowIsolate",
1806 "IgnoreOnIsolate",
1807 "DefaultDependencies"))
1808 return bus_append_parse_boolean(m, field, eq);
1809
1810 if (STR_IN_SET(field, "JobTimeoutSec",
1811 "JobRunningTimeoutSec",
1812 "StartLimitIntervalSec"))
1813 return bus_append_parse_sec_rename(m, field, eq);
1814
1815 if (streq(field, "StartLimitBurst"))
1816 return bus_append_safe_atou(m, field, eq);
1817
1818 if (STR_IN_SET(field, "SuccessActionExitStatus",
1819 "FailureActionExitStatus")) {
1820 if (isempty(eq))
1821 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1822 else {
1823 uint8_t u;
1824
1825 r = safe_atou8(eq, &u);
1826 if (r < 0)
1827 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1828
1829 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1830 }
1831 if (r < 0)
1832 return bus_log_create_error(r);
1833
1834 return 1;
1835 }
1836
1837 if (unit_dependency_from_string(field) >= 0 ||
1838 STR_IN_SET(field, "Documentation",
1839 "RequiresMountsFor"))
1840 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
1841
1842 t = condition_type_from_string(field);
1843 if (t >= 0)
1844 is_condition = true;
1845 else
1846 t = assert_type_from_string(field);
1847 if (t >= 0) {
1848 if (isempty(eq))
1849 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1850 else {
1851 const char *p = eq;
1852 int trigger, negate;
1853
1854 trigger = *p == '|';
1855 if (trigger)
1856 p++;
1857
1858 negate = *p == '!';
1859 if (negate)
1860 p++;
1861
1862 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1863 field, trigger, negate, p);
1864 }
1865 if (r < 0)
1866 return bus_log_create_error(r);
1867
1868 return 1;
1869 }
1870
1871 return 0;
1872 }
1873
1874 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1875 const char *eq, *field;
1876 int r;
1877
1878 assert(m);
1879 assert(assignment);
1880
1881 eq = strchr(assignment, '=');
1882 if (!eq)
1883 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1884 "Not an assignment: %s", assignment);
1885
1886 field = strndupa(assignment, eq - assignment);
1887 eq++;
1888
1889 switch (t) {
1890 case UNIT_SERVICE:
1891 r = bus_append_cgroup_property(m, field, eq);
1892 if (r != 0)
1893 return r;
1894
1895 r = bus_append_execute_property(m, field, eq);
1896 if (r != 0)
1897 return r;
1898
1899 r = bus_append_kill_property(m, field, eq);
1900 if (r != 0)
1901 return r;
1902
1903 r = bus_append_service_property(m, field, eq);
1904 if (r != 0)
1905 return r;
1906 break;
1907
1908 case UNIT_SOCKET:
1909 r = bus_append_cgroup_property(m, field, eq);
1910 if (r != 0)
1911 return r;
1912
1913 r = bus_append_execute_property(m, field, eq);
1914 if (r != 0)
1915 return r;
1916
1917 r = bus_append_kill_property(m, field, eq);
1918 if (r != 0)
1919 return r;
1920
1921 r = bus_append_socket_property(m, field, eq);
1922 if (r != 0)
1923 return r;
1924 break;
1925
1926 case UNIT_TIMER:
1927 r = bus_append_timer_property(m, field, eq);
1928 if (r != 0)
1929 return r;
1930 break;
1931
1932 case UNIT_PATH:
1933 r = bus_append_path_property(m, field, eq);
1934 if (r != 0)
1935 return r;
1936 break;
1937
1938 case UNIT_SLICE:
1939 r = bus_append_cgroup_property(m, field, eq);
1940 if (r != 0)
1941 return r;
1942 break;
1943
1944 case UNIT_SCOPE:
1945 r = bus_append_cgroup_property(m, field, eq);
1946 if (r != 0)
1947 return r;
1948
1949 r = bus_append_kill_property(m, field, eq);
1950 if (r != 0)
1951 return r;
1952
1953 r = bus_append_scope_property(m, field, eq);
1954 if (r != 0)
1955 return r;
1956 break;
1957
1958 case UNIT_MOUNT:
1959 r = bus_append_cgroup_property(m, field, eq);
1960 if (r != 0)
1961 return r;
1962
1963 r = bus_append_execute_property(m, field, eq);
1964 if (r != 0)
1965 return r;
1966
1967 r = bus_append_kill_property(m, field, eq);
1968 if (r != 0)
1969 return r;
1970
1971 r = bus_append_mount_property(m, field, eq);
1972 if (r != 0)
1973 return r;
1974
1975 break;
1976
1977 case UNIT_AUTOMOUNT:
1978 r = bus_append_automount_property(m, field, eq);
1979 if (r != 0)
1980 return r;
1981
1982 break;
1983
1984 case UNIT_TARGET:
1985 case UNIT_DEVICE:
1986 case UNIT_SWAP:
1987 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1988 "Not supported unit type");
1989
1990 default:
1991 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1992 "Invalid unit type");
1993 }
1994
1995 r = bus_append_unit_property(m, field, eq);
1996 if (r != 0)
1997 return r;
1998
1999 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2000 "Unknown assignment: %s", assignment);
2001 }
2002
2003 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
2004 char **i;
2005 int r;
2006
2007 assert(m);
2008
2009 STRV_FOREACH(i, l) {
2010 r = bus_append_unit_property_assignment(m, t, *i);
2011 if (r < 0)
2012 return r;
2013 }
2014
2015 return 0;
2016 }
2017
2018 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
2019 const char *type, *path, *source;
2020 int r;
2021
2022 /* changes is dereferenced when calling unit_file_dump_changes() later,
2023 * so we have to make sure this is not NULL. */
2024 assert(changes);
2025 assert(n_changes);
2026
2027 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2028 if (r < 0)
2029 return bus_log_parse_error(r);
2030
2031 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2032 /* We expect only "success" changes to be sent over the bus.
2033 Hence, reject anything negative. */
2034 UnitFileChangeType ch = unit_file_change_type_from_string(type);
2035
2036 if (ch < 0) {
2037 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
2038 continue;
2039 }
2040
2041 r = unit_file_changes_add(changes, n_changes, ch, path, source);
2042 if (r < 0)
2043 return r;
2044 }
2045 if (r < 0)
2046 return bus_log_parse_error(r);
2047
2048 r = sd_bus_message_exit_container(m);
2049 if (r < 0)
2050 return bus_log_parse_error(r);
2051
2052 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
2053 return 0;
2054 }
2055
2056 int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2057 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2058 _cleanup_free_ char *path = NULL;
2059 int r;
2060
2061 path = unit_dbus_path_from_name(name);
2062 if (!path)
2063 return log_oom();
2064
2065 /* This function warns on it's own, because otherwise it'd be awkward to pass
2066 * the dbus error message around. */
2067
2068 r = sd_bus_get_property_string(
2069 bus,
2070 "org.freedesktop.systemd1",
2071 path,
2072 "org.freedesktop.systemd1.Unit",
2073 "LoadState",
2074 &error,
2075 load_state);
2076 if (r < 0)
2077 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2078
2079 return 0;
2080 }