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