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