]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
core: introduce NUMAPolicy and NUMAMask options
[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 (streq(field, "NUMAPolicy")) {
1053 r = mpol_from_string(eq);
1054 if (r < 0)
1055 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1056
1057 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1058 if (r < 0)
1059 return bus_log_create_error(r);
1060
1061 return 1;
1062 }
1063
1064 if (streq(field, "NUMAMask")) {
1065 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1066 _cleanup_free_ uint8_t *array = NULL;
1067 size_t allocated;
1068
1069 r = parse_cpu_set(eq, &nodes);
1070 if (r < 0)
1071 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1072
1073 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1074 if (r < 0)
1075 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1076
1077 return bus_append_byte_array(m, field, array, allocated);
1078 }
1079
1080 if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
1081 int whitelist = 1;
1082 const char *p = eq;
1083
1084 if (*p == '~') {
1085 whitelist = 0;
1086 p++;
1087 }
1088
1089 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1090 if (r < 0)
1091 return bus_log_create_error(r);
1092
1093 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1094 if (r < 0)
1095 return bus_log_create_error(r);
1096
1097 r = sd_bus_message_open_container(m, 'v', "(bas)");
1098 if (r < 0)
1099 return bus_log_create_error(r);
1100
1101 r = sd_bus_message_open_container(m, 'r', "bas");
1102 if (r < 0)
1103 return bus_log_create_error(r);
1104
1105 r = sd_bus_message_append_basic(m, 'b', &whitelist);
1106 if (r < 0)
1107 return bus_log_create_error(r);
1108
1109 r = sd_bus_message_open_container(m, 'a', "s");
1110 if (r < 0)
1111 return bus_log_create_error(r);
1112
1113 for (;;) {
1114 _cleanup_free_ char *word = NULL;
1115
1116 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1117 if (r == 0)
1118 break;
1119 if (r == -ENOMEM)
1120 return log_oom();
1121 if (r < 0)
1122 return log_error_errno(r, "Invalid syntax: %s", eq);
1123
1124 r = sd_bus_message_append_basic(m, 's', word);
1125 if (r < 0)
1126 return bus_log_create_error(r);
1127 }
1128
1129 r = sd_bus_message_close_container(m);
1130 if (r < 0)
1131 return bus_log_create_error(r);
1132
1133 r = sd_bus_message_close_container(m);
1134 if (r < 0)
1135 return bus_log_create_error(r);
1136
1137 r = sd_bus_message_close_container(m);
1138 if (r < 0)
1139 return bus_log_create_error(r);
1140
1141 r = sd_bus_message_close_container(m);
1142 if (r < 0)
1143 return bus_log_create_error(r);
1144
1145 return 1;
1146 }
1147
1148 if (streq(field, "RestrictNamespaces")) {
1149 bool invert = false;
1150 unsigned long flags;
1151
1152 r = parse_boolean(eq);
1153 if (r > 0)
1154 flags = 0;
1155 else if (r == 0)
1156 flags = NAMESPACE_FLAGS_ALL;
1157 else {
1158 if (eq[0] == '~') {
1159 invert = true;
1160 eq++;
1161 }
1162
1163 r = namespace_flags_from_string(eq, &flags);
1164 if (r < 0)
1165 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1166 }
1167
1168 if (invert)
1169 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1170
1171 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1172 if (r < 0)
1173 return bus_log_create_error(r);
1174
1175 return 1;
1176 }
1177
1178 if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) {
1179 const char *p = eq;
1180
1181 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1182 if (r < 0)
1183 return bus_log_create_error(r);
1184
1185 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1186 if (r < 0)
1187 return bus_log_create_error(r);
1188
1189 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1190 if (r < 0)
1191 return bus_log_create_error(r);
1192
1193 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1194 if (r < 0)
1195 return bus_log_create_error(r);
1196
1197 for (;;) {
1198 _cleanup_free_ char *source = NULL, *destination = NULL;
1199 char *s = NULL, *d = NULL;
1200 bool ignore_enoent = false;
1201 uint64_t flags = MS_REC;
1202
1203 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1204 if (r < 0)
1205 return log_error_errno(r, "Failed to parse argument: %m");
1206 if (r == 0)
1207 break;
1208
1209 s = source;
1210 if (s[0] == '-') {
1211 ignore_enoent = true;
1212 s++;
1213 }
1214
1215 if (p && p[-1] == ':') {
1216 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1217 if (r < 0)
1218 return log_error_errno(r, "Failed to parse argument: %m");
1219 if (r == 0)
1220 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1221 "Missing argument after ':': %s",
1222 eq);
1223
1224 d = destination;
1225
1226 if (p && p[-1] == ':') {
1227 _cleanup_free_ char *options = NULL;
1228
1229 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
1230 if (r < 0)
1231 return log_error_errno(r, "Failed to parse argument: %m");
1232
1233 if (isempty(options) || streq(options, "rbind"))
1234 flags = MS_REC;
1235 else if (streq(options, "norbind"))
1236 flags = 0;
1237 else
1238 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1239 "Unknown options: %s",
1240 eq);
1241 }
1242 } else
1243 d = s;
1244
1245 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1246 if (r < 0)
1247 return bus_log_create_error(r);
1248 }
1249
1250 r = sd_bus_message_close_container(m);
1251 if (r < 0)
1252 return bus_log_create_error(r);
1253
1254 r = sd_bus_message_close_container(m);
1255 if (r < 0)
1256 return bus_log_create_error(r);
1257
1258 r = sd_bus_message_close_container(m);
1259 if (r < 0)
1260 return bus_log_create_error(r);
1261
1262 return 1;
1263 }
1264
1265 if (streq(field, "TemporaryFileSystem")) {
1266 const char *p = eq;
1267
1268 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1269 if (r < 0)
1270 return bus_log_create_error(r);
1271
1272 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1273 if (r < 0)
1274 return bus_log_create_error(r);
1275
1276 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1277 if (r < 0)
1278 return bus_log_create_error(r);
1279
1280 r = sd_bus_message_open_container(m, 'a', "(ss)");
1281 if (r < 0)
1282 return bus_log_create_error(r);
1283
1284 for (;;) {
1285 _cleanup_free_ char *word = NULL, *path = NULL;
1286 const char *w;
1287
1288 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1289 if (r < 0)
1290 return log_error_errno(r, "Failed to parse argument: %m");
1291 if (r == 0)
1292 break;
1293
1294 w = word;
1295 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1296 if (r < 0)
1297 return log_error_errno(r, "Failed to parse argument: %m");
1298 if (r == 0)
1299 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1300 "Failed to parse argument: %s",
1301 p);
1302
1303 r = sd_bus_message_append(m, "(ss)", path, w);
1304 if (r < 0)
1305 return bus_log_create_error(r);
1306 }
1307
1308 r = sd_bus_message_close_container(m);
1309 if (r < 0)
1310 return bus_log_create_error(r);
1311
1312 r = sd_bus_message_close_container(m);
1313 if (r < 0)
1314 return bus_log_create_error(r);
1315
1316 r = sd_bus_message_close_container(m);
1317 if (r < 0)
1318 return bus_log_create_error(r);
1319
1320 return 1;
1321 }
1322
1323 return 0;
1324 }
1325
1326 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
1327
1328 if (streq(field, "KillMode"))
1329
1330 return bus_append_string(m, field, eq);
1331
1332 if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
1333
1334 return bus_append_parse_boolean(m, field, eq);
1335
1336 if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1337
1338 return bus_append_signal_from_string(m, field, eq);
1339
1340 return 0;
1341 }
1342
1343 static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
1344
1345 if (STR_IN_SET(field, "What", "Where", "Options", "Type"))
1346
1347 return bus_append_string(m, field, eq);
1348
1349 if (streq(field, "TimeoutSec"))
1350
1351 return bus_append_parse_sec_rename(m, field, eq);
1352
1353 if (streq(field, "DirectoryMode"))
1354
1355 return bus_append_parse_mode(m, field, eq);
1356
1357 if (STR_IN_SET(field, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1358
1359 return bus_append_parse_boolean(m, field, eq);
1360
1361 return 0;
1362 }
1363
1364 static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1365 int r;
1366
1367 if (streq(field, "MakeDirectory"))
1368
1369 return bus_append_parse_boolean(m, field, eq);
1370
1371 if (streq(field, "DirectoryMode"))
1372
1373 return bus_append_parse_mode(m, field, eq);
1374
1375 if (STR_IN_SET(field,
1376 "PathExists", "PathExistsGlob", "PathChanged",
1377 "PathModified", "DirectoryNotEmpty")) {
1378
1379 if (isempty(eq))
1380 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1381 else
1382 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1383 if (r < 0)
1384 return bus_log_create_error(r);
1385
1386 return 1;
1387 }
1388
1389 return 0;
1390 }
1391
1392 static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
1393 int r;
1394
1395 if (STR_IN_SET(field,
1396 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1397 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1398
1399 return bus_append_string(m, field, eq);
1400
1401 if (STR_IN_SET(field, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1402
1403 return bus_append_parse_boolean(m, field, eq);
1404
1405 if (STR_IN_SET(field, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1406
1407 return bus_append_parse_sec_rename(m, field, eq);
1408
1409 if (streq(field, "TimeoutSec")) {
1410
1411 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1412 if (r < 0)
1413 return r;
1414
1415 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1416 }
1417
1418 if (streq(field, "FileDescriptorStoreMax"))
1419
1420 return bus_append_safe_atou(m, field, eq);
1421
1422 if (STR_IN_SET(field,
1423 "ExecStartPre", "ExecStart", "ExecStartPost",
1424 "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1425 "ExecReload", "ExecStop", "ExecStopPost"))
1426 return bus_append_exec_command(m, field, eq);
1427
1428 if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1429 _cleanup_free_ int *status = NULL, *signal = NULL;
1430 size_t sz_status = 0, sz_signal = 0;
1431 const char *p;
1432
1433 for (p = eq;;) {
1434 _cleanup_free_ char *word = NULL;
1435 int val;
1436
1437 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1438 if (r == 0)
1439 break;
1440 if (r == -ENOMEM)
1441 return log_oom();
1442 if (r < 0)
1443 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
1444
1445 r = safe_atoi(word, &val);
1446 if (r < 0) {
1447 val = signal_from_string(word);
1448 if (val < 0)
1449 return log_error_errno(r, "Invalid status or signal %s in %s: %m", word, field);
1450
1451 signal = reallocarray(signal, sz_signal + 1, sizeof(int));
1452 if (!signal)
1453 return log_oom();
1454
1455 signal[sz_signal++] = val;
1456 } else {
1457 status = reallocarray(status, sz_status + 1, sizeof(int));
1458 if (!status)
1459 return log_oom();
1460
1461 status[sz_status++] = val;
1462 }
1463 }
1464
1465 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1466 if (r < 0)
1467 return bus_log_create_error(r);
1468
1469 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1470 if (r < 0)
1471 return bus_log_create_error(r);
1472
1473 r = sd_bus_message_open_container(m, 'v', "(aiai)");
1474 if (r < 0)
1475 return bus_log_create_error(r);
1476
1477 r = sd_bus_message_open_container(m, 'r', "aiai");
1478 if (r < 0)
1479 return bus_log_create_error(r);
1480
1481 r = sd_bus_message_append_array(m, 'i', status, sz_status);
1482 if (r < 0)
1483 return bus_log_create_error(r);
1484
1485 r = sd_bus_message_append_array(m, 'i', signal, sz_signal);
1486 if (r < 0)
1487 return bus_log_create_error(r);
1488
1489 r = sd_bus_message_close_container(m);
1490 if (r < 0)
1491 return bus_log_create_error(r);
1492
1493 r = sd_bus_message_close_container(m);
1494 if (r < 0)
1495 return bus_log_create_error(r);
1496
1497 r = sd_bus_message_close_container(m);
1498 if (r < 0)
1499 return bus_log_create_error(r);
1500
1501 return 1;
1502 }
1503
1504 return 0;
1505 }
1506
1507 static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1508 int r;
1509
1510 if (STR_IN_SET(field,
1511 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1512 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1513
1514 return bus_append_parse_boolean(m, field, eq);
1515
1516 if (STR_IN_SET(field, "Priority", "IPTTL", "Mark"))
1517
1518 return bus_append_safe_atoi(m, field, eq);
1519
1520 if (streq(field, "IPTOS"))
1521
1522 return bus_append_ip_tos_from_string(m, field, eq);
1523
1524 if (STR_IN_SET(field, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1525
1526 return bus_append_safe_atou(m, field, eq);
1527
1528 if (STR_IN_SET(field, "SocketMode", "DirectoryMode"))
1529
1530 return bus_append_parse_mode(m, field, eq);
1531
1532 if (STR_IN_SET(field, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1533
1534 return bus_append_safe_atoi64(m, field, eq);
1535
1536 if (STR_IN_SET(field, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1537
1538 return bus_append_parse_sec_rename(m, field, eq);
1539
1540 if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1541
1542 return bus_append_parse_size(m, field, eq, 1024);
1543
1544 if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1545
1546 return bus_append_exec_command(m, field, eq);
1547
1548 if (STR_IN_SET(field,
1549 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1550 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1551 "SocketUser", "SocketGroup"))
1552
1553 return bus_append_string(m, field, eq);
1554
1555 if (streq(field, "Symlinks"))
1556
1557 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1558
1559 if (streq(field, "SocketProtocol"))
1560
1561 return bus_append_parse_ip_protocol(m, field, eq);
1562
1563 if (STR_IN_SET(field,
1564 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1565 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1566
1567 if (isempty(eq))
1568 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
1569 else
1570 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
1571 if (r < 0)
1572 return bus_log_create_error(r);
1573
1574 return 1;
1575 }
1576
1577 return 0;
1578 }
1579 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
1580 int r;
1581
1582 if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
1583 "OnTimezoneChange", "OnClockChange"))
1584
1585 return bus_append_parse_boolean(m, field, eq);
1586
1587 if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec"))
1588
1589 return bus_append_parse_sec_rename(m, field, eq);
1590
1591 if (STR_IN_SET(field,
1592 "OnActiveSec", "OnBootSec", "OnStartupSec",
1593 "OnUnitActiveSec","OnUnitInactiveSec")) {
1594
1595 if (isempty(eq))
1596 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1597 else {
1598 usec_t t;
1599 r = parse_sec(eq, &t);
1600 if (r < 0)
1601 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
1602
1603 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1604 }
1605 if (r < 0)
1606 return bus_log_create_error(r);
1607
1608 return 1;
1609 }
1610
1611 if (streq(field, "OnCalendar")) {
1612
1613 if (isempty(eq))
1614 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1615 else
1616 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1617 if (r < 0)
1618 return bus_log_create_error(r);
1619
1620 return 1;
1621 }
1622
1623 return 0;
1624 }
1625
1626 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
1627 ConditionType t = _CONDITION_TYPE_INVALID;
1628 bool is_condition = false;
1629 int r;
1630
1631 if (STR_IN_SET(field,
1632 "Description", "SourcePath", "OnFailureJobMode",
1633 "JobTimeoutAction", "JobTimeoutRebootArgument",
1634 "StartLimitAction", "FailureAction", "SuccessAction",
1635 "RebootArgument", "CollectMode"))
1636
1637 return bus_append_string(m, field, eq);
1638
1639 if (STR_IN_SET(field,
1640 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1641 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1642
1643 return bus_append_parse_boolean(m, field, eq);
1644
1645 if (STR_IN_SET(field, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1646
1647 return bus_append_parse_sec_rename(m, field, eq);
1648
1649 if (streq(field, "StartLimitBurst"))
1650
1651 return bus_append_safe_atou(m, field, eq);
1652
1653 if (STR_IN_SET(field, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1654
1655 if (isempty(eq))
1656 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1657 else {
1658 uint8_t u;
1659
1660 r = safe_atou8(eq, &u);
1661 if (r < 0)
1662 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1663
1664 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1665 }
1666 if (r < 0)
1667 return bus_log_create_error(r);
1668
1669 return 1;
1670 }
1671
1672 if (unit_dependency_from_string(field) >= 0 ||
1673 STR_IN_SET(field, "Documentation", "RequiresMountsFor"))
1674
1675 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1676
1677 t = condition_type_from_string(field);
1678 if (t >= 0)
1679 is_condition = true;
1680 else
1681 t = assert_type_from_string(field);
1682 if (t >= 0) {
1683 if (isempty(eq))
1684 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1685 else {
1686 const char *p = eq;
1687 int trigger, negate;
1688
1689 trigger = *p == '|';
1690 if (trigger)
1691 p++;
1692
1693 negate = *p == '!';
1694 if (negate)
1695 p++;
1696
1697 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1698 field, trigger, negate, p);
1699 }
1700 if (r < 0)
1701 return bus_log_create_error(r);
1702
1703 return 1;
1704 }
1705
1706 return 0;
1707 }
1708
1709 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1710 const char *eq, *field;
1711 int r;
1712
1713 assert(m);
1714 assert(assignment);
1715
1716 eq = strchr(assignment, '=');
1717 if (!eq)
1718 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1719 "Not an assignment: %s", assignment);
1720
1721 field = strndupa(assignment, eq - assignment);
1722 eq++;
1723
1724 switch (t) {
1725 case UNIT_SERVICE:
1726 r = bus_append_cgroup_property(m, field, eq);
1727 if (r != 0)
1728 return r;
1729
1730 r = bus_append_execute_property(m, field, eq);
1731 if (r != 0)
1732 return r;
1733
1734 r = bus_append_kill_property(m, field, eq);
1735 if (r != 0)
1736 return r;
1737
1738 r = bus_append_service_property(m, field, eq);
1739 if (r != 0)
1740 return r;
1741 break;
1742
1743 case UNIT_SOCKET:
1744 r = bus_append_cgroup_property(m, field, eq);
1745 if (r != 0)
1746 return r;
1747
1748 r = bus_append_execute_property(m, field, eq);
1749 if (r != 0)
1750 return r;
1751
1752 r = bus_append_kill_property(m, field, eq);
1753 if (r != 0)
1754 return r;
1755
1756 r = bus_append_socket_property(m, field, eq);
1757 if (r != 0)
1758 return r;
1759 break;
1760
1761 case UNIT_TIMER:
1762 r = bus_append_timer_property(m, field, eq);
1763 if (r != 0)
1764 return r;
1765 break;
1766
1767 case UNIT_PATH:
1768 r = bus_append_path_property(m, field, eq);
1769 if (r != 0)
1770 return r;
1771 break;
1772
1773 case UNIT_SLICE:
1774 r = bus_append_cgroup_property(m, field, eq);
1775 if (r != 0)
1776 return r;
1777 break;
1778
1779 case UNIT_SCOPE:
1780
1781 if (streq(field, "TimeoutStopSec"))
1782 return bus_append_parse_sec_rename(m, field, eq);
1783
1784 r = bus_append_cgroup_property(m, field, eq);
1785 if (r != 0)
1786 return r;
1787
1788 r = bus_append_kill_property(m, field, eq);
1789 if (r != 0)
1790 return r;
1791 break;
1792
1793 case UNIT_MOUNT:
1794 r = bus_append_cgroup_property(m, field, eq);
1795 if (r != 0)
1796 return r;
1797
1798 r = bus_append_execute_property(m, field, eq);
1799 if (r != 0)
1800 return r;
1801
1802 r = bus_append_kill_property(m, field, eq);
1803 if (r != 0)
1804 return r;
1805
1806 r = bus_append_mount_property(m, field, eq);
1807 if (r != 0)
1808 return r;
1809
1810 break;
1811
1812 case UNIT_AUTOMOUNT:
1813 r = bus_append_automount_property(m, field, eq);
1814 if (r != 0)
1815 return r;
1816
1817 break;
1818
1819 case UNIT_TARGET:
1820 case UNIT_DEVICE:
1821 case UNIT_SWAP:
1822 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1823 "Not supported unit type");
1824
1825 default:
1826 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1827 "Invalid unit type");
1828 }
1829
1830 r = bus_append_unit_property(m, field, eq);
1831 if (r != 0)
1832 return r;
1833
1834 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1835 "Unknown assignment: %s", assignment);
1836 }
1837
1838 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
1839 char **i;
1840 int r;
1841
1842 assert(m);
1843
1844 STRV_FOREACH(i, l) {
1845 r = bus_append_unit_property_assignment(m, t, *i);
1846 if (r < 0)
1847 return r;
1848 }
1849
1850 return 0;
1851 }
1852
1853 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
1854 const char *type, *path, *source;
1855 int r;
1856
1857 /* changes is dereferenced when calling unit_file_dump_changes() later,
1858 * so we have to make sure this is not NULL. */
1859 assert(changes);
1860 assert(n_changes);
1861
1862 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1863 if (r < 0)
1864 return bus_log_parse_error(r);
1865
1866 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1867 /* We expect only "success" changes to be sent over the bus.
1868 Hence, reject anything negative. */
1869 UnitFileChangeType ch = unit_file_change_type_from_string(type);
1870
1871 if (ch < 0) {
1872 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
1873 continue;
1874 }
1875
1876 r = unit_file_changes_add(changes, n_changes, ch, path, source);
1877 if (r < 0)
1878 return r;
1879 }
1880 if (r < 0)
1881 return bus_log_parse_error(r);
1882
1883 r = sd_bus_message_exit_container(m);
1884 if (r < 0)
1885 return bus_log_parse_error(r);
1886
1887 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
1888 return 0;
1889 }
1890
1891 int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
1892 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1893 _cleanup_free_ char *path = NULL;
1894 int r;
1895
1896 path = unit_dbus_path_from_name(name);
1897 if (!path)
1898 return log_oom();
1899
1900 /* This function warns on it's own, because otherwise it'd be awkward to pass
1901 * the dbus error message around. */
1902
1903 r = sd_bus_get_property_string(
1904 bus,
1905 "org.freedesktop.systemd1",
1906 path,
1907 "org.freedesktop.systemd1.Unit",
1908 "LoadState",
1909 &error,
1910 load_state);
1911 if (r < 0)
1912 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
1913
1914 return 0;
1915 }