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