]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
Merge pull request #12424 from poettering/logind-brightness
[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 = strappend(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_QUOTES|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_QUOTES|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_QUOTES);
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_QUOTES);
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 return 0;
762 }
763
764 static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
765
766 if (streq(field, "Where"))
767
768 return bus_append_string(m, field, eq);
769
770 if (streq(field, "DirectoryMode"))
771
772 return bus_append_parse_mode(m, field, eq);
773
774 if (streq(field, "TimeoutIdleSec"))
775
776 return bus_append_parse_sec_rename(m, field, eq);
777
778 return 0;
779 }
780
781 static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
782 const char *suffix;
783 int r;
784
785 if (STR_IN_SET(field,
786 "User", "Group",
787 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
788 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
789 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
790 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
791
792 return bus_append_string(m, field, eq);
793
794 if (STR_IN_SET(field,
795 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
796 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
797 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
798 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
799 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
800 "ProtectHostname", "RestrictSUIDSGID"))
801
802 return bus_append_parse_boolean(m, field, eq);
803
804 if (STR_IN_SET(field,
805 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
806 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
807 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
808 "SupplementaryGroups", "SystemCallArchitectures"))
809
810 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
811
812 if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax"))
813
814 return bus_append_log_level_from_string(m, field, eq);
815
816 if (streq(field, "SyslogFacility"))
817
818 return bus_append_log_facility_unshifted_from_string(m, field, eq);
819
820 if (streq(field, "SecureBits"))
821
822 return bus_append_secure_bits_from_string(m, field, eq);
823
824 if (streq(field, "CPUSchedulingPolicy"))
825
826 return bus_append_sched_policy_from_string(m, field, eq);
827
828 if (STR_IN_SET(field, "CPUSchedulingPriority", "OOMScoreAdjust"))
829
830 return bus_append_safe_atoi(m, field, eq);
831
832 if (streq(field, "Nice"))
833
834 return bus_append_parse_nice(m, field, eq);
835
836 if (streq(field, "SystemCallErrorNumber"))
837
838 return bus_append_parse_errno(m, field, eq);
839
840 if (streq(field, "IOSchedulingClass"))
841
842 return bus_append_ioprio_class_from_string(m, field, eq);
843
844 if (streq(field, "IOSchedulingPriority"))
845
846 return bus_append_ioprio_parse_priority(m, field, eq);
847
848 if (STR_IN_SET(field,
849 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
850 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
851
852 return bus_append_parse_mode(m, field, eq);
853
854 if (streq(field, "TimerSlackNSec"))
855
856 return bus_append_parse_nsec(m, field, eq);
857
858 if (streq(field, "LogRateLimitIntervalSec"))
859
860 return bus_append_parse_sec_rename(m, field, eq);
861
862 if (streq(field, "LogRateLimitBurst"))
863
864 return bus_append_safe_atou(m, field, eq);
865
866 if (streq(field, "MountFlags"))
867
868 return bus_append_mount_propagation_flags_from_string(m, field, eq);
869
870 if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment"))
871
872 return bus_append_strv(m, field, eq, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
873
874 if (streq(field, "EnvironmentFile")) {
875
876 if (isempty(eq))
877 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
878 else
879 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
880 eq[0] == '-' ? eq + 1 : eq,
881 eq[0] == '-');
882 if (r < 0)
883 return bus_log_create_error(r);
884
885 return 1;
886 }
887
888 if (streq(field, "LogExtraFields")) {
889
890 r = sd_bus_message_open_container(m, 'r', "sv");
891 if (r < 0)
892 return bus_log_create_error(r);
893
894 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
895 if (r < 0)
896 return bus_log_create_error(r);
897
898 r = sd_bus_message_open_container(m, 'v', "aay");
899 if (r < 0)
900 return bus_log_create_error(r);
901
902 r = sd_bus_message_open_container(m, 'a', "ay");
903 if (r < 0)
904 return bus_log_create_error(r);
905
906 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
907 if (r < 0)
908 return bus_log_create_error(r);
909
910 r = sd_bus_message_close_container(m);
911 if (r < 0)
912 return bus_log_create_error(r);
913
914 r = sd_bus_message_close_container(m);
915 if (r < 0)
916 return bus_log_create_error(r);
917
918 r = sd_bus_message_close_container(m);
919 if (r < 0)
920 return bus_log_create_error(r);
921
922 return 1;
923 }
924
925 if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) {
926 const char *n, *appended;
927
928 if ((n = startswith(eq, "fd:"))) {
929 appended = strjoina(field, "FileDescriptorName");
930 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
931 } else if ((n = startswith(eq, "file:"))) {
932 appended = strjoina(field, "File");
933 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
934 } else if ((n = startswith(eq, "append:"))) {
935 appended = strjoina(field, "FileToAppend");
936 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
937 } else
938 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
939 if (r < 0)
940 return bus_log_create_error(r);
941
942 return 1;
943 }
944
945 if (streq(field, "StandardInputText")) {
946 _cleanup_free_ char *unescaped = NULL;
947
948 r = cunescape(eq, 0, &unescaped);
949 if (r < 0)
950 return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
951
952 if (!strextend(&unescaped, "\n", NULL))
953 return log_oom();
954
955 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
956 * interface anyway */
957
958 return bus_append_byte_array(m, field, unescaped, strlen(unescaped));
959 }
960
961 if (streq(field, "StandardInputData")) {
962 _cleanup_free_ void *decoded = NULL;
963 size_t sz;
964
965 r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
966 if (r < 0)
967 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
968
969 return bus_append_byte_array(m, field, decoded, sz);
970 }
971
972 if ((suffix = startswith(field, "Limit"))) {
973 int rl;
974
975 rl = rlimit_from_string(suffix);
976 if (rl >= 0) {
977 const char *sn;
978 struct rlimit l;
979
980 r = rlimit_parse(rl, eq, &l);
981 if (r < 0)
982 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
983
984 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
985 if (r < 0)
986 return bus_log_create_error(r);
987
988 sn = strjoina(field, "Soft");
989 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
990 if (r < 0)
991 return bus_log_create_error(r);
992
993 return 1;
994 }
995 }
996
997 if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
998 int ignore = 0;
999 const char *s = eq;
1000
1001 if (eq[0] == '-') {
1002 ignore = 1;
1003 s = eq + 1;
1004 }
1005
1006 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
1007 if (r < 0)
1008 return bus_log_create_error(r);
1009
1010 return 1;
1011 }
1012
1013 if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) {
1014 uint64_t sum = 0;
1015 bool invert = false;
1016 const char *p = eq;
1017
1018 if (*p == '~') {
1019 invert = true;
1020 p++;
1021 }
1022
1023 r = capability_set_from_string(p, &sum);
1024 if (r < 0)
1025 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
1026
1027 sum = invert ? ~sum : sum;
1028
1029 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
1030 if (r < 0)
1031 return bus_log_create_error(r);
1032
1033 return 1;
1034 }
1035
1036 if (streq(field, "CPUAffinity")) {
1037 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
1038 _cleanup_free_ uint8_t *array = NULL;
1039 size_t allocated;
1040
1041 r = parse_cpu_set(eq, &cpuset);
1042 if (r < 0)
1043 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1044
1045 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1046 if (r < 0)
1047 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1048
1049 return bus_append_byte_array(m, field, array, allocated);
1050 }
1051
1052 if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
1053 int whitelist = 1;
1054 const char *p = eq;
1055
1056 if (*p == '~') {
1057 whitelist = 0;
1058 p++;
1059 }
1060
1061 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1062 if (r < 0)
1063 return bus_log_create_error(r);
1064
1065 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1066 if (r < 0)
1067 return bus_log_create_error(r);
1068
1069 r = sd_bus_message_open_container(m, 'v', "(bas)");
1070 if (r < 0)
1071 return bus_log_create_error(r);
1072
1073 r = sd_bus_message_open_container(m, 'r', "bas");
1074 if (r < 0)
1075 return bus_log_create_error(r);
1076
1077 r = sd_bus_message_append_basic(m, 'b', &whitelist);
1078 if (r < 0)
1079 return bus_log_create_error(r);
1080
1081 r = sd_bus_message_open_container(m, 'a', "s");
1082 if (r < 0)
1083 return bus_log_create_error(r);
1084
1085 for (;;) {
1086 _cleanup_free_ char *word = NULL;
1087
1088 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1089 if (r == 0)
1090 break;
1091 if (r == -ENOMEM)
1092 return log_oom();
1093 if (r < 0)
1094 return log_error_errno(r, "Invalid syntax: %s", eq);
1095
1096 r = sd_bus_message_append_basic(m, 's', word);
1097 if (r < 0)
1098 return bus_log_create_error(r);
1099 }
1100
1101 r = sd_bus_message_close_container(m);
1102 if (r < 0)
1103 return bus_log_create_error(r);
1104
1105 r = sd_bus_message_close_container(m);
1106 if (r < 0)
1107 return bus_log_create_error(r);
1108
1109 r = sd_bus_message_close_container(m);
1110 if (r < 0)
1111 return bus_log_create_error(r);
1112
1113 r = sd_bus_message_close_container(m);
1114 if (r < 0)
1115 return bus_log_create_error(r);
1116
1117 return 1;
1118 }
1119
1120 if (streq(field, "RestrictNamespaces")) {
1121 bool invert = false;
1122 unsigned long flags;
1123
1124 r = parse_boolean(eq);
1125 if (r > 0)
1126 flags = 0;
1127 else if (r == 0)
1128 flags = NAMESPACE_FLAGS_ALL;
1129 else {
1130 if (eq[0] == '~') {
1131 invert = true;
1132 eq++;
1133 }
1134
1135 r = namespace_flags_from_string(eq, &flags);
1136 if (r < 0)
1137 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1138 }
1139
1140 if (invert)
1141 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1142
1143 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1144 if (r < 0)
1145 return bus_log_create_error(r);
1146
1147 return 1;
1148 }
1149
1150 if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) {
1151 const char *p = eq;
1152
1153 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1154 if (r < 0)
1155 return bus_log_create_error(r);
1156
1157 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1158 if (r < 0)
1159 return bus_log_create_error(r);
1160
1161 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1162 if (r < 0)
1163 return bus_log_create_error(r);
1164
1165 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1166 if (r < 0)
1167 return bus_log_create_error(r);
1168
1169 for (;;) {
1170 _cleanup_free_ char *source = NULL, *destination = NULL;
1171 char *s = NULL, *d = NULL;
1172 bool ignore_enoent = false;
1173 uint64_t flags = MS_REC;
1174
1175 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1176 if (r < 0)
1177 return log_error_errno(r, "Failed to parse argument: %m");
1178 if (r == 0)
1179 break;
1180
1181 s = source;
1182 if (s[0] == '-') {
1183 ignore_enoent = true;
1184 s++;
1185 }
1186
1187 if (p && p[-1] == ':') {
1188 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1189 if (r < 0)
1190 return log_error_errno(r, "Failed to parse argument: %m");
1191 if (r == 0)
1192 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1193 "Missing argument after ':': %s",
1194 eq);
1195
1196 d = destination;
1197
1198 if (p && p[-1] == ':') {
1199 _cleanup_free_ char *options = NULL;
1200
1201 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
1202 if (r < 0)
1203 return log_error_errno(r, "Failed to parse argument: %m");
1204
1205 if (isempty(options) || streq(options, "rbind"))
1206 flags = MS_REC;
1207 else if (streq(options, "norbind"))
1208 flags = 0;
1209 else
1210 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1211 "Unknown options: %s",
1212 eq);
1213 }
1214 } else
1215 d = s;
1216
1217 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1218 if (r < 0)
1219 return bus_log_create_error(r);
1220 }
1221
1222 r = sd_bus_message_close_container(m);
1223 if (r < 0)
1224 return bus_log_create_error(r);
1225
1226 r = sd_bus_message_close_container(m);
1227 if (r < 0)
1228 return bus_log_create_error(r);
1229
1230 r = sd_bus_message_close_container(m);
1231 if (r < 0)
1232 return bus_log_create_error(r);
1233
1234 return 1;
1235 }
1236
1237 if (streq(field, "TemporaryFileSystem")) {
1238 const char *p = eq;
1239
1240 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1241 if (r < 0)
1242 return bus_log_create_error(r);
1243
1244 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1245 if (r < 0)
1246 return bus_log_create_error(r);
1247
1248 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1249 if (r < 0)
1250 return bus_log_create_error(r);
1251
1252 r = sd_bus_message_open_container(m, 'a', "(ss)");
1253 if (r < 0)
1254 return bus_log_create_error(r);
1255
1256 for (;;) {
1257 _cleanup_free_ char *word = NULL, *path = NULL;
1258 const char *w;
1259
1260 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1261 if (r < 0)
1262 return log_error_errno(r, "Failed to parse argument: %m");
1263 if (r == 0)
1264 break;
1265
1266 w = word;
1267 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1268 if (r < 0)
1269 return log_error_errno(r, "Failed to parse argument: %m");
1270 if (r == 0)
1271 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1272 "Failed to parse argument: %s",
1273 p);
1274
1275 r = sd_bus_message_append(m, "(ss)", path, w);
1276 if (r < 0)
1277 return bus_log_create_error(r);
1278 }
1279
1280 r = sd_bus_message_close_container(m);
1281 if (r < 0)
1282 return bus_log_create_error(r);
1283
1284 r = sd_bus_message_close_container(m);
1285 if (r < 0)
1286 return bus_log_create_error(r);
1287
1288 r = sd_bus_message_close_container(m);
1289 if (r < 0)
1290 return bus_log_create_error(r);
1291
1292 return 1;
1293 }
1294
1295 return 0;
1296 }
1297
1298 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
1299
1300 if (streq(field, "KillMode"))
1301
1302 return bus_append_string(m, field, eq);
1303
1304 if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
1305
1306 return bus_append_parse_boolean(m, field, eq);
1307
1308 if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1309
1310 return bus_append_signal_from_string(m, field, eq);
1311
1312 return 0;
1313 }
1314
1315 static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
1316
1317 if (STR_IN_SET(field, "What", "Where", "Options", "Type"))
1318
1319 return bus_append_string(m, field, eq);
1320
1321 if (streq(field, "TimeoutSec"))
1322
1323 return bus_append_parse_sec_rename(m, field, eq);
1324
1325 if (streq(field, "DirectoryMode"))
1326
1327 return bus_append_parse_mode(m, field, eq);
1328
1329 if (STR_IN_SET(field, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1330
1331 return bus_append_parse_boolean(m, field, eq);
1332
1333 return 0;
1334 }
1335
1336 static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1337 int r;
1338
1339 if (streq(field, "MakeDirectory"))
1340
1341 return bus_append_parse_boolean(m, field, eq);
1342
1343 if (streq(field, "DirectoryMode"))
1344
1345 return bus_append_parse_mode(m, field, eq);
1346
1347 if (STR_IN_SET(field,
1348 "PathExists", "PathExistsGlob", "PathChanged",
1349 "PathModified", "DirectoryNotEmpty")) {
1350
1351 if (isempty(eq))
1352 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1353 else
1354 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1355 if (r < 0)
1356 return bus_log_create_error(r);
1357
1358 return 1;
1359 }
1360
1361 return 0;
1362 }
1363
1364 static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
1365 int r;
1366
1367 if (STR_IN_SET(field,
1368 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1369 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1370
1371 return bus_append_string(m, field, eq);
1372
1373 if (STR_IN_SET(field, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1374
1375 return bus_append_parse_boolean(m, field, eq);
1376
1377 if (STR_IN_SET(field, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1378
1379 return bus_append_parse_sec_rename(m, field, eq);
1380
1381 if (streq(field, "TimeoutSec")) {
1382
1383 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1384 if (r < 0)
1385 return r;
1386
1387 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1388 }
1389
1390 if (streq(field, "FileDescriptorStoreMax"))
1391
1392 return bus_append_safe_atou(m, field, eq);
1393
1394 if (STR_IN_SET(field,
1395 "ExecStartPre", "ExecStart", "ExecStartPost",
1396 "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1397 "ExecReload", "ExecStop", "ExecStopPost"))
1398 return bus_append_exec_command(m, field, eq);
1399
1400 if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1401 _cleanup_free_ int *status = NULL, *signal = NULL;
1402 size_t sz_status = 0, sz_signal = 0;
1403 const char *p;
1404
1405 for (p = eq;;) {
1406 _cleanup_free_ char *word = NULL;
1407 int val;
1408
1409 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1410 if (r == 0)
1411 break;
1412 if (r == -ENOMEM)
1413 return log_oom();
1414 if (r < 0)
1415 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
1416
1417 r = safe_atoi(word, &val);
1418 if (r < 0) {
1419 val = signal_from_string(word);
1420 if (val < 0)
1421 return log_error_errno(r, "Invalid status or signal %s in %s: %m", word, field);
1422
1423 signal = reallocarray(signal, sz_signal + 1, sizeof(int));
1424 if (!signal)
1425 return log_oom();
1426
1427 signal[sz_signal++] = val;
1428 } else {
1429 status = reallocarray(status, sz_status + 1, sizeof(int));
1430 if (!status)
1431 return log_oom();
1432
1433 status[sz_status++] = val;
1434 }
1435 }
1436
1437 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1438 if (r < 0)
1439 return bus_log_create_error(r);
1440
1441 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1442 if (r < 0)
1443 return bus_log_create_error(r);
1444
1445 r = sd_bus_message_open_container(m, 'v', "(aiai)");
1446 if (r < 0)
1447 return bus_log_create_error(r);
1448
1449 r = sd_bus_message_open_container(m, 'r', "aiai");
1450 if (r < 0)
1451 return bus_log_create_error(r);
1452
1453 r = sd_bus_message_append_array(m, 'i', status, sz_status);
1454 if (r < 0)
1455 return bus_log_create_error(r);
1456
1457 r = sd_bus_message_append_array(m, 'i', signal, sz_signal);
1458 if (r < 0)
1459 return bus_log_create_error(r);
1460
1461 r = sd_bus_message_close_container(m);
1462 if (r < 0)
1463 return bus_log_create_error(r);
1464
1465 r = sd_bus_message_close_container(m);
1466 if (r < 0)
1467 return bus_log_create_error(r);
1468
1469 r = sd_bus_message_close_container(m);
1470 if (r < 0)
1471 return bus_log_create_error(r);
1472
1473 return 1;
1474 }
1475
1476 return 0;
1477 }
1478
1479 static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1480 int r;
1481
1482 if (STR_IN_SET(field,
1483 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1484 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1485
1486 return bus_append_parse_boolean(m, field, eq);
1487
1488 if (STR_IN_SET(field, "Priority", "IPTTL", "Mark"))
1489
1490 return bus_append_safe_atoi(m, field, eq);
1491
1492 if (streq(field, "IPTOS"))
1493
1494 return bus_append_ip_tos_from_string(m, field, eq);
1495
1496 if (STR_IN_SET(field, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1497
1498 return bus_append_safe_atou(m, field, eq);
1499
1500 if (STR_IN_SET(field, "SocketMode", "DirectoryMode"))
1501
1502 return bus_append_parse_mode(m, field, eq);
1503
1504 if (STR_IN_SET(field, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1505
1506 return bus_append_safe_atoi64(m, field, eq);
1507
1508 if (STR_IN_SET(field, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1509
1510 return bus_append_parse_sec_rename(m, field, eq);
1511
1512 if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1513
1514 return bus_append_parse_size(m, field, eq, 1024);
1515
1516 if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1517
1518 return bus_append_exec_command(m, field, eq);
1519
1520 if (STR_IN_SET(field,
1521 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1522 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1523 "SocketUser", "SocketGroup"))
1524
1525 return bus_append_string(m, field, eq);
1526
1527 if (streq(field, "Symlinks"))
1528
1529 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1530
1531 if (streq(field, "SocketProtocol"))
1532
1533 return bus_append_parse_ip_protocol(m, field, eq);
1534
1535 if (STR_IN_SET(field,
1536 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1537 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1538
1539 if (isempty(eq))
1540 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
1541 else
1542 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
1543 if (r < 0)
1544 return bus_log_create_error(r);
1545
1546 return 1;
1547 }
1548
1549 return 0;
1550 }
1551 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
1552 int r;
1553
1554 if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
1555 "OnTimezoneChange", "OnClockChange"))
1556
1557 return bus_append_parse_boolean(m, field, eq);
1558
1559 if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec"))
1560
1561 return bus_append_parse_sec_rename(m, field, eq);
1562
1563 if (STR_IN_SET(field,
1564 "OnActiveSec", "OnBootSec", "OnStartupSec",
1565 "OnUnitActiveSec","OnUnitInactiveSec")) {
1566
1567 if (isempty(eq))
1568 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1569 else {
1570 usec_t t;
1571 r = parse_sec(eq, &t);
1572 if (r < 0)
1573 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
1574
1575 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1576 }
1577 if (r < 0)
1578 return bus_log_create_error(r);
1579
1580 return 1;
1581 }
1582
1583 if (streq(field, "OnCalendar")) {
1584
1585 if (isempty(eq))
1586 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1587 else
1588 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1589 if (r < 0)
1590 return bus_log_create_error(r);
1591
1592 return 1;
1593 }
1594
1595 return 0;
1596 }
1597
1598 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
1599 ConditionType t = _CONDITION_TYPE_INVALID;
1600 bool is_condition = false;
1601 int r;
1602
1603 if (STR_IN_SET(field,
1604 "Description", "SourcePath", "OnFailureJobMode",
1605 "JobTimeoutAction", "JobTimeoutRebootArgument",
1606 "StartLimitAction", "FailureAction", "SuccessAction",
1607 "RebootArgument", "CollectMode"))
1608
1609 return bus_append_string(m, field, eq);
1610
1611 if (STR_IN_SET(field,
1612 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1613 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1614
1615 return bus_append_parse_boolean(m, field, eq);
1616
1617 if (STR_IN_SET(field, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1618
1619 return bus_append_parse_sec_rename(m, field, eq);
1620
1621 if (streq(field, "StartLimitBurst"))
1622
1623 return bus_append_safe_atou(m, field, eq);
1624
1625 if (STR_IN_SET(field, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1626
1627 if (isempty(eq))
1628 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1629 else {
1630 uint8_t u;
1631
1632 r = safe_atou8(eq, &u);
1633 if (r < 0)
1634 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1635
1636 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1637 }
1638 if (r < 0)
1639 return bus_log_create_error(r);
1640
1641 return 1;
1642 }
1643
1644 if (unit_dependency_from_string(field) >= 0 ||
1645 STR_IN_SET(field, "Documentation", "RequiresMountsFor"))
1646
1647 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1648
1649 t = condition_type_from_string(field);
1650 if (t >= 0)
1651 is_condition = true;
1652 else
1653 t = assert_type_from_string(field);
1654 if (t >= 0) {
1655 if (isempty(eq))
1656 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1657 else {
1658 const char *p = eq;
1659 int trigger, negate;
1660
1661 trigger = *p == '|';
1662 if (trigger)
1663 p++;
1664
1665 negate = *p == '!';
1666 if (negate)
1667 p++;
1668
1669 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1670 field, trigger, negate, p);
1671 }
1672 if (r < 0)
1673 return bus_log_create_error(r);
1674
1675 return 1;
1676 }
1677
1678 return 0;
1679 }
1680
1681 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1682 const char *eq, *field;
1683 int r;
1684
1685 assert(m);
1686 assert(assignment);
1687
1688 eq = strchr(assignment, '=');
1689 if (!eq)
1690 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1691 "Not an assignment: %s", assignment);
1692
1693 field = strndupa(assignment, eq - assignment);
1694 eq++;
1695
1696 switch (t) {
1697 case UNIT_SERVICE:
1698 r = bus_append_cgroup_property(m, field, eq);
1699 if (r != 0)
1700 return r;
1701
1702 r = bus_append_execute_property(m, field, eq);
1703 if (r != 0)
1704 return r;
1705
1706 r = bus_append_kill_property(m, field, eq);
1707 if (r != 0)
1708 return r;
1709
1710 r = bus_append_service_property(m, field, eq);
1711 if (r != 0)
1712 return r;
1713 break;
1714
1715 case UNIT_SOCKET:
1716 r = bus_append_cgroup_property(m, field, eq);
1717 if (r != 0)
1718 return r;
1719
1720 r = bus_append_execute_property(m, field, eq);
1721 if (r != 0)
1722 return r;
1723
1724 r = bus_append_kill_property(m, field, eq);
1725 if (r != 0)
1726 return r;
1727
1728 r = bus_append_socket_property(m, field, eq);
1729 if (r != 0)
1730 return r;
1731 break;
1732
1733 case UNIT_TIMER:
1734 r = bus_append_timer_property(m, field, eq);
1735 if (r != 0)
1736 return r;
1737 break;
1738
1739 case UNIT_PATH:
1740 r = bus_append_path_property(m, field, eq);
1741 if (r != 0)
1742 return r;
1743 break;
1744
1745 case UNIT_SLICE:
1746 r = bus_append_cgroup_property(m, field, eq);
1747 if (r != 0)
1748 return r;
1749 break;
1750
1751 case UNIT_SCOPE:
1752
1753 if (streq(field, "TimeoutStopSec"))
1754 return bus_append_parse_sec_rename(m, field, eq);
1755
1756 r = bus_append_cgroup_property(m, field, eq);
1757 if (r != 0)
1758 return r;
1759
1760 r = bus_append_kill_property(m, field, eq);
1761 if (r != 0)
1762 return r;
1763 break;
1764
1765 case UNIT_MOUNT:
1766 r = bus_append_cgroup_property(m, field, eq);
1767 if (r != 0)
1768 return r;
1769
1770 r = bus_append_execute_property(m, field, eq);
1771 if (r != 0)
1772 return r;
1773
1774 r = bus_append_kill_property(m, field, eq);
1775 if (r != 0)
1776 return r;
1777
1778 r = bus_append_mount_property(m, field, eq);
1779 if (r != 0)
1780 return r;
1781
1782 break;
1783
1784 case UNIT_AUTOMOUNT:
1785 r = bus_append_automount_property(m, field, eq);
1786 if (r != 0)
1787 return r;
1788
1789 break;
1790
1791 case UNIT_TARGET:
1792 case UNIT_DEVICE:
1793 case UNIT_SWAP:
1794 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1795 "Not supported unit type");
1796
1797 default:
1798 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1799 "Invalid unit type");
1800 }
1801
1802 r = bus_append_unit_property(m, field, eq);
1803 if (r != 0)
1804 return r;
1805
1806 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1807 "Unknown assignment: %s", assignment);
1808 }
1809
1810 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
1811 char **i;
1812 int r;
1813
1814 assert(m);
1815
1816 STRV_FOREACH(i, l) {
1817 r = bus_append_unit_property_assignment(m, t, *i);
1818 if (r < 0)
1819 return r;
1820 }
1821
1822 return 0;
1823 }
1824
1825 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
1826 const char *type, *path, *source;
1827 int r;
1828
1829 /* changes is dereferenced when calling unit_file_dump_changes() later,
1830 * so we have to make sure this is not NULL. */
1831 assert(changes);
1832 assert(n_changes);
1833
1834 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1835 if (r < 0)
1836 return bus_log_parse_error(r);
1837
1838 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1839 /* We expect only "success" changes to be sent over the bus.
1840 Hence, reject anything negative. */
1841 UnitFileChangeType ch = unit_file_change_type_from_string(type);
1842
1843 if (ch < 0) {
1844 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
1845 continue;
1846 }
1847
1848 r = unit_file_changes_add(changes, n_changes, ch, path, source);
1849 if (r < 0)
1850 return r;
1851 }
1852 if (r < 0)
1853 return bus_log_parse_error(r);
1854
1855 r = sd_bus_message_exit_container(m);
1856 if (r < 0)
1857 return bus_log_parse_error(r);
1858
1859 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
1860 return 0;
1861 }
1862
1863 int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
1864 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1865 _cleanup_free_ char *path = NULL;
1866 int r;
1867
1868 path = unit_dbus_path_from_name(name);
1869 if (!path)
1870 return log_oom();
1871
1872 /* This function warns on it's own, because otherwise it'd be awkward to pass
1873 * the dbus error message around. */
1874
1875 r = sd_bus_get_property_string(
1876 bus,
1877 "org.freedesktop.systemd1",
1878 path,
1879 "org.freedesktop.systemd1.Unit",
1880 "LoadState",
1881 &error,
1882 load_state);
1883 if (r < 0)
1884 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
1885
1886 return 0;
1887 }