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