]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-unit-util.c
bus-unit-util: make dependency settings can take multiple units
[thirdparty/systemd.git] / src / shared / bus-unit-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2016 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include "alloc-util.h"
22 #include "bus-internal.h"
23 #include "bus-unit-util.h"
24 #include "bus-util.h"
25 #include "cap-list.h"
26 #include "cgroup-util.h"
27 #include "cpu-set-util.h"
28 #include "env-util.h"
29 #include "errno-list.h"
30 #include "escape.h"
31 #include "hashmap.h"
32 #include "hexdecoct.h"
33 #include "hostname-util.h"
34 #include "in-addr-util.h"
35 #include "list.h"
36 #include "locale-util.h"
37 #include "mount-util.h"
38 #include "nsflags.h"
39 #include "parse-util.h"
40 #include "path-util.h"
41 #include "process-util.h"
42 #include "rlimit-util.h"
43 #include "securebits-util.h"
44 #include "signal-util.h"
45 #include "socket-protocol-list.h"
46 #include "string-util.h"
47 #include "syslog-util.h"
48 #include "terminal-util.h"
49 #include "unit-def.h"
50 #include "user-util.h"
51 #include "utf8.h"
52 #include "util.h"
53
54 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
55 assert(message);
56 assert(u);
57
58 u->machine = NULL;
59
60 return sd_bus_message_read(
61 message,
62 "(ssssssouso)",
63 &u->id,
64 &u->description,
65 &u->load_state,
66 &u->active_state,
67 &u->sub_state,
68 &u->following,
69 &u->unit_path,
70 &u->job_id,
71 &u->job_type,
72 &u->job_path);
73 }
74
75 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
76 static int bus_append_##parse_func(sd_bus_message *m, const char *field, const char *eq) { \
77 type val; \
78 int r; \
79 \
80 r = parse_func(eq, &val); \
81 if (r < 0) \
82 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
83 \
84 r = sd_bus_message_append(m, "(sv)", field, bus_type, (cast_type) val); \
85 if (r < 0) \
86 return bus_log_create_error(r); \
87 \
88 return 1; \
89 }
90
91 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
92 static int bus_append_##parse_func(sd_bus_message *m, const char *field, const char *eq) { \
93 int r; \
94 \
95 r = parse_func(eq); \
96 if (r < 0) { \
97 log_error("Failed to parse %s: %s", field, eq); \
98 return -EINVAL; \
99 } \
100 \
101 r = sd_bus_message_append(m, "(sv)", field, bus_type, (int32_t) r); \
102 if (r < 0) \
103 return bus_log_create_error(r); \
104 \
105 return 1; \
106 }
107
108 DEFINE_BUS_APPEND_PARSE("b", parse_boolean)
109 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string)
110 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string)
111 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string)
112 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string)
113 DEFINE_BUS_APPEND_PARSE("i", parse_errno)
114 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string)
115 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string)
116 DEFINE_BUS_APPEND_PARSE("i", signal_from_string_try_harder)
117 DEFINE_BUS_APPEND_PARSE("i", socket_protocol_from_name)
118 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority)
119 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice)
120 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi)
121 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec)
122 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse)
123 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse)
124 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse)
125 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string)
126 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, usec_t, parse_sec)
127 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode)
128 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou)
129 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64)
130
131 static inline int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
132 int r;
133
134 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
135 if (r < 0)
136 return bus_log_create_error(r);
137
138 return 1;
139 }
140
141 static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
142 const char *p;
143 int r;
144
145 r = sd_bus_message_open_container(m, 'r', "sv");
146 if (r < 0)
147 return bus_log_create_error(r);
148
149 r = sd_bus_message_append_basic(m, 's', field);
150 if (r < 0)
151 return bus_log_create_error(r);
152
153 r = sd_bus_message_open_container(m, 'v', "as");
154 if (r < 0)
155 return bus_log_create_error(r);
156
157 r = sd_bus_message_open_container(m, 'a', "s");
158 if (r < 0)
159 return bus_log_create_error(r);
160
161 for (p = eq;;) {
162 _cleanup_free_ char *word = NULL;
163
164 r = extract_first_word(&p, &word, NULL, flags);
165 if (r == 0)
166 break;
167 if (r == -ENOMEM)
168 return log_oom();
169 if (r < 0)
170 return log_error_errno(r, "Invalid syntax: %s", eq);
171
172 r = sd_bus_message_append_basic(m, 's', word);
173 if (r < 0)
174 return bus_log_create_error(r);
175 }
176
177 r = sd_bus_message_close_container(m);
178 if (r < 0)
179 return bus_log_create_error(r);
180
181 r = sd_bus_message_close_container(m);
182 if (r < 0)
183 return bus_log_create_error(r);
184
185 r = sd_bus_message_close_container(m);
186 if (r < 0)
187 return bus_log_create_error(r);
188
189 return 1;
190 }
191
192 static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
193 int r;
194
195 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
196 if (r < 0)
197 return bus_log_create_error(r);
198
199 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
200 if (r < 0)
201 return bus_log_create_error(r);
202
203 r = sd_bus_message_open_container(m, 'v', "ay");
204 if (r < 0)
205 return bus_log_create_error(r);
206
207 r = sd_bus_message_append_array(m, 'y', buf, n);
208 if (r < 0)
209 return bus_log_create_error(r);
210
211 r = sd_bus_message_close_container(m);
212 if (r < 0)
213 return bus_log_create_error(r);
214
215 r = sd_bus_message_close_container(m);
216 if (r < 0)
217 return bus_log_create_error(r);
218
219 return 1;
220 }
221
222 static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
223 char *n;
224 usec_t t;
225 size_t l;
226 int r;
227
228 r = parse_sec(eq, &t);
229 if (r < 0)
230 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
231
232 l = strlen(field);
233 n = newa(char, l + 2);
234 /* Change suffix Sec → USec */
235 strcpy(mempcpy(n, field, l - 3), "USec");
236
237 r = sd_bus_message_append(m, "(sv)", n, "t", t);
238 if (r < 0)
239 return bus_log_create_error(r);
240
241 return 1;
242 }
243
244 static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
245 uint64_t v;
246 int r;
247
248 r = parse_size(eq, base, &v);
249 if (r < 0)
250 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
251
252 r = sd_bus_message_append(m, "(sv)", field, "t", v);
253 if (r < 0)
254 return bus_log_create_error(r);
255
256 return 1;
257 }
258
259 static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
260 bool ignore_failure = false, explicit_path = false, done = false;
261 _cleanup_strv_free_ char **l = NULL;
262 _cleanup_free_ char *path = NULL;
263 int r;
264
265 do {
266 switch (*eq) {
267
268 case '-':
269 if (ignore_failure)
270 done = true;
271 else {
272 ignore_failure = true;
273 eq++;
274 }
275 break;
276
277 case '@':
278 if (explicit_path)
279 done = true;
280 else {
281 explicit_path = true;
282 eq++;
283 }
284 break;
285
286 case '+':
287 case '!':
288 /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */
289 log_error("Sorry, but +, ! and !! are currently not supported for transient services.");
290 return -EOPNOTSUPP;
291
292 default:
293 done = true;
294 break;
295 }
296 } while (!done);
297
298 if (explicit_path) {
299 r = extract_first_word(&eq, &path, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
300 if (r < 0)
301 return log_error_errno(r, "Failed to parse path: %m");
302 }
303
304 r = strv_split_extract(&l, eq, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
305 if (r < 0)
306 return log_error_errno(r, "Failed to parse command line: %m");
307
308 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
309 if (r < 0)
310 return bus_log_create_error(r);
311
312 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
313 if (r < 0)
314 return bus_log_create_error(r);
315
316 r = sd_bus_message_open_container(m, 'v', "a(sasb)");
317 if (r < 0)
318 return bus_log_create_error(r);
319
320 r = sd_bus_message_open_container(m, 'a', "(sasb)");
321 if (r < 0)
322 return bus_log_create_error(r);
323
324 if (!strv_isempty(l)) {
325
326 r = sd_bus_message_open_container(m, 'r', "sasb");
327 if (r < 0)
328 return bus_log_create_error(r);
329
330 r = sd_bus_message_append(m, "s", path ?: l[0]);
331 if (r < 0)
332 return bus_log_create_error(r);
333
334 r = sd_bus_message_append_strv(m, l);
335 if (r < 0)
336 return bus_log_create_error(r);
337
338 r = sd_bus_message_append(m, "b", ignore_failure);
339 if (r < 0)
340 return bus_log_create_error(r);
341
342 r = sd_bus_message_close_container(m);
343 if (r < 0)
344 return bus_log_create_error(r);
345 }
346
347 r = sd_bus_message_close_container(m);
348 if (r < 0)
349 return bus_log_create_error(r);
350
351 r = sd_bus_message_close_container(m);
352 if (r < 0)
353 return bus_log_create_error(r);
354
355 r = sd_bus_message_close_container(m);
356 if (r < 0)
357 return bus_log_create_error(r);
358
359 return 1;
360 }
361
362 static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
363 int r;
364
365 assert(m);
366 assert(prefix);
367
368 r = sd_bus_message_open_container(m, 'r', "iayu");
369 if (r < 0)
370 return r;
371
372 r = sd_bus_message_append(m, "i", family);
373 if (r < 0)
374 return r;
375
376 r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
377 if (r < 0)
378 return r;
379
380 r = sd_bus_message_append(m, "u", prefixlen);
381 if (r < 0)
382 return r;
383
384 return sd_bus_message_close_container(m);
385 }
386
387 static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
388 int r;
389
390 if (STR_IN_SET(field, "DevicePolicy", "Slice"))
391
392 return bus_append_string(m, field, eq);
393
394 if (STR_IN_SET(field,
395 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
396 "TasksAccounting", "IPAccounting"))
397
398 return bus_append_parse_boolean(m, field, eq);
399
400 if (STR_IN_SET(field, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
401
402 return bus_append_cg_weight_parse(m, field, eq);
403
404 if (STR_IN_SET(field, "CPUShares", "StartupCPUShares"))
405
406 return bus_append_cg_cpu_shares_parse(m, field, eq);
407
408 if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight"))
409
410 return bus_append_cg_blkio_weight_parse(m, field, eq);
411
412 if (streq(field, "Delegate")) {
413
414 r = parse_boolean(eq);
415 if (r < 0)
416 return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_QUOTES);
417
418 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
419 if (r < 0)
420 return bus_log_create_error(r);
421
422 return 1;
423 }
424
425 if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
426 uint64_t val;
427
428 if (isempty(eq) || streq(eq, "infinity")) {
429 r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
430 if (r < 0)
431 return bus_log_create_error(r);
432 return 1;
433 }
434
435 r = parse_percent(eq);
436 if (r >= 0) {
437 char *n;
438
439 /* When this is a percentage we'll convert this into a relative value in the range
440 * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related
441 * ones). This way the physical memory size can be determined server-side */
442
443 n = strjoina(field, "Scale");
444 r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
445 if (r < 0)
446 return bus_log_create_error(r);
447
448 return 1;
449 }
450
451 if (streq(field, "TasksMax"))
452 r = safe_atou64(eq, &val);
453 else
454 r = parse_size(eq, 1024, &val);
455
456 if (r < 0)
457 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
458
459 r = sd_bus_message_append(m, "(sv)", field, "t", val);
460 if (r < 0)
461 return bus_log_create_error(r);
462
463 return 1;
464 }
465
466 if (streq(field, "CPUQuota")) {
467
468 if (isempty(eq))
469 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
470 else {
471 r = parse_percent_unbounded(eq);
472 if (r <= 0) {
473 log_error_errno(r, "CPU quota '%s' invalid.", eq);
474 return -EINVAL;
475 }
476
477 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (usec_t) r * USEC_PER_SEC / 100U);
478 }
479
480 if (r < 0)
481 return bus_log_create_error(r);
482
483 return 1;
484 }
485
486 if (streq(field, "DeviceAllow")) {
487
488 if (isempty(eq))
489 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
490 else {
491 const char *path, *rwm, *e;
492
493 e = strchr(eq, ' ');
494 if (e) {
495 path = strndupa(eq, e - eq);
496 rwm = e+1;
497 } else {
498 path = eq;
499 rwm = "";
500 }
501
502 if (!is_deviceallow_pattern(path)) {
503 log_error("%s is not a device file in /dev.", path);
504 return -EINVAL;
505 }
506
507 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, rwm);
508 }
509
510 if (r < 0)
511 return bus_log_create_error(r);
512
513 return 1;
514 }
515
516 if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
517
518 if (isempty(eq))
519 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
520 else {
521 const char *path, *bandwidth, *e;
522 uint64_t bytes;
523
524 e = strchr(eq, ' ');
525 if (e) {
526 path = strndupa(eq, e - eq);
527 bandwidth = e+1;
528 } else {
529 log_error("Failed to parse %s value %s.", field, eq);
530 return -EINVAL;
531 }
532
533 if (!path_startswith(path, "/dev")) {
534 log_error("%s is not a device file in /dev.", path);
535 return -EINVAL;
536 }
537
538 if (streq(bandwidth, "infinity")) {
539 bytes = CGROUP_LIMIT_MAX;
540 } else {
541 r = parse_size(bandwidth, 1000, &bytes);
542 if (r < 0)
543 return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
544 }
545
546 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
547 }
548
549 if (r < 0)
550 return bus_log_create_error(r);
551
552 return 1;
553 }
554
555 if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) {
556
557 if (isempty(eq))
558 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
559 else {
560 const char *path, *weight, *e;
561 uint64_t u;
562
563 e = strchr(eq, ' ');
564 if (e) {
565 path = strndupa(eq, e - eq);
566 weight = e+1;
567 } else {
568 log_error("Failed to parse %s value %s.", field, eq);
569 return -EINVAL;
570 }
571
572 if (!path_startswith(path, "/dev")) {
573 log_error("%s is not a device file in /dev.", path);
574 return -EINVAL;
575 }
576
577 r = safe_atou64(weight, &u);
578 if (r < 0)
579 return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
580
581 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
582 }
583
584 if (r < 0)
585 return bus_log_create_error(r);
586
587 return 1;
588 }
589
590 if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) {
591 unsigned char prefixlen;
592 union in_addr_union prefix = {};
593 int family;
594
595 if (isempty(eq)) {
596 r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
597 if (r < 0)
598 return bus_log_create_error(r);
599
600 return 1;
601 }
602
603 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
604 if (r < 0)
605 return bus_log_create_error(r);
606
607 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
608 if (r < 0)
609 return bus_log_create_error(r);
610
611 r = sd_bus_message_open_container(m, 'v', "a(iayu)");
612 if (r < 0)
613 return bus_log_create_error(r);
614
615 r = sd_bus_message_open_container(m, 'a', "(iayu)");
616 if (r < 0)
617 return bus_log_create_error(r);
618
619 if (streq(eq, "any")) {
620 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
621
622 r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
623 if (r < 0)
624 return bus_log_create_error(r);
625
626 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
627 if (r < 0)
628 return bus_log_create_error(r);
629
630 } else if (is_localhost(eq)) {
631 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
632
633 prefix.in.s_addr = htobe32(0x7f000000);
634 r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
635 if (r < 0)
636 return bus_log_create_error(r);
637
638 prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
639 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
640 if (r < 0)
641 return r;
642
643 } else if (streq(eq, "link-local")) {
644 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
645
646 prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
647 r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
648 if (r < 0)
649 return bus_log_create_error(r);
650
651 prefix.in6 = (struct in6_addr) {
652 .s6_addr32[0] = htobe32(0xfe800000)
653 };
654 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
655 if (r < 0)
656 return bus_log_create_error(r);
657
658 } else if (streq(eq, "multicast")) {
659 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
660
661 prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
662 r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
663 if (r < 0)
664 return bus_log_create_error(r);
665
666 prefix.in6 = (struct in6_addr) {
667 .s6_addr32[0] = htobe32(0xff000000)
668 };
669 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
670 if (r < 0)
671 return bus_log_create_error(r);
672
673 } else {
674 r = in_addr_prefix_from_string_auto(eq, &family, &prefix, &prefixlen);
675 if (r < 0)
676 return log_error_errno(r, "Failed to parse IP address prefix: %s", eq);
677
678 r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
679 if (r < 0)
680 return bus_log_create_error(r);
681 }
682
683 r = sd_bus_message_close_container(m);
684 if (r < 0)
685 return bus_log_create_error(r);
686
687 r = sd_bus_message_close_container(m);
688 if (r < 0)
689 return bus_log_create_error(r);
690
691 r = sd_bus_message_close_container(m);
692 if (r < 0)
693 return bus_log_create_error(r);
694
695 return 1;
696 }
697
698 return 0;
699 }
700
701 static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
702 int r, rl;
703
704 if (STR_IN_SET(field,
705 "User", "Group",
706 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
707 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
708 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
709 "RuntimeDirectoryPreserve", "Personality", "KeyringMode"))
710
711 return bus_append_string(m, field, eq);
712
713 if (STR_IN_SET(field,
714 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
715 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
716 "NoNewPrivileges", "SyslogLevelPrefix",
717 "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
718 "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
719 "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality"))
720
721 return bus_append_parse_boolean(m, field, eq);
722
723 if (STR_IN_SET(field,
724 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
725 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
726 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
727 "SupplementaryGroups", "SystemCallArchitectures"))
728
729 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
730
731 if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax"))
732
733 return bus_append_log_level_from_string(m, field, eq);
734
735 if (streq(field, "SyslogFacility"))
736
737 return bus_append_log_facility_unshifted_from_string(m, field, eq);
738
739 if (streq(field, "SecureBits"))
740
741 return bus_append_secure_bits_from_string(m, field, eq);
742
743 if (streq(field, "CPUSchedulingPolicy"))
744
745 return bus_append_sched_policy_from_string(m, field, eq);
746
747 if (STR_IN_SET(field, "CPUSchedulingPriority", "OOMScoreAdjust"))
748
749 return bus_append_safe_atoi(m, field, eq);
750
751 if (streq(field, "Nice"))
752
753 return bus_append_parse_nice(m, field, eq);
754
755 if (streq(field, "SystemCallErrorNumber"))
756
757 return bus_append_parse_errno(m, field, eq);
758
759 if (streq(field, "IOSchedulingClass"))
760
761 return bus_append_ioprio_class_from_string(m, field, eq);
762
763 if (streq(field, "IOSchedulingPriority"))
764
765 return bus_append_ioprio_parse_priority(m, field, eq);
766
767 if (STR_IN_SET(field,
768 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
769 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
770
771 return bus_append_parse_mode(m, field, eq);
772
773 if (streq(field, "TimerSlackNSec"))
774
775 return bus_append_parse_nsec(m, field, eq);
776
777 if (streq(field, "MountFlags"))
778
779 return bus_append_mount_propagation_flags_from_string(m, field, eq);
780
781 if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment"))
782
783 return bus_append_strv(m, field, eq, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
784
785 if (streq(field, "EnvironmentFile")) {
786
787 if (isempty(eq))
788 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
789 else
790 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
791 eq[0] == '-' ? eq + 1 : eq,
792 eq[0] == '-');
793 if (r < 0)
794 return bus_log_create_error(r);
795
796 return 1;
797 }
798
799 if (streq(field, "LogExtraFields")) {
800
801 r = sd_bus_message_open_container(m, 'r', "sv");
802 if (r < 0)
803 return bus_log_create_error(r);
804
805 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
806 if (r < 0)
807 return bus_log_create_error(r);
808
809 r = sd_bus_message_open_container(m, 'v', "aay");
810 if (r < 0)
811 return bus_log_create_error(r);
812
813 r = sd_bus_message_open_container(m, 'a', "ay");
814 if (r < 0)
815 return bus_log_create_error(r);
816
817 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
818 if (r < 0)
819 return bus_log_create_error(r);
820
821 r = sd_bus_message_close_container(m);
822 if (r < 0)
823 return bus_log_create_error(r);
824
825 r = sd_bus_message_close_container(m);
826 if (r < 0)
827 return bus_log_create_error(r);
828
829 r = sd_bus_message_close_container(m);
830 if (r < 0)
831 return bus_log_create_error(r);
832
833 return 1;
834 }
835
836 if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) {
837 const char *n, *appended;
838
839 if ((n = startswith(eq, "fd:"))) {
840 appended = strjoina(field, "FileDescriptorName");
841 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
842 } else if ((n = startswith(eq, "file:"))) {
843 appended = strjoina(field, "File");
844 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
845 } else
846 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
847
848 if (r < 0)
849 return bus_log_create_error(r);
850
851 return 1;
852 }
853
854 if (streq(field, "StandardInputText")) {
855 _cleanup_free_ char *unescaped = NULL;
856
857 r = cunescape(eq, 0, &unescaped);
858 if (r < 0)
859 return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
860
861 if (!strextend(&unescaped, "\n", NULL))
862 return log_oom();
863
864 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
865 * interface anyway */
866
867 return bus_append_byte_array(m, field, unescaped, strlen(unescaped));
868 }
869
870 if (streq(field, "StandardInputData")) {
871 _cleanup_free_ void *decoded = NULL;
872 size_t sz;
873
874 r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
875 if (r < 0)
876 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
877
878 return bus_append_byte_array(m, field, decoded, sz);
879 }
880
881 rl = rlimit_from_string(field);
882 if (rl >= 0) {
883 const char *sn;
884 struct rlimit l;
885
886 r = rlimit_parse(rl, eq, &l);
887 if (r < 0)
888 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
889
890 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
891 if (r < 0)
892 return bus_log_create_error(r);
893
894 sn = strjoina(field, "Soft");
895 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
896 if (r < 0)
897 return bus_log_create_error(r);
898
899 return 1;
900 }
901
902 if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
903 int ignore = 0;
904 const char *s = eq;
905
906 if (eq[0] == '-') {
907 ignore = 1;
908 s = eq + 1;
909 }
910
911 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
912 if (r < 0)
913 return bus_log_create_error(r);
914
915 return 1;
916 }
917
918 if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) {
919 uint64_t sum = 0;
920 bool invert = false;
921 const char *p = eq;
922
923 if (*p == '~') {
924 invert = true;
925 p++;
926 }
927
928 r = capability_set_from_string(p, &sum);
929 if (r < 0)
930 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
931
932 sum = invert ? ~sum : sum;
933
934 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
935 if (r < 0)
936 return bus_log_create_error(r);
937
938 return 1;
939 }
940
941 if (streq(field, "CPUAffinity")) {
942 _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
943
944 r = parse_cpu_set(eq, &cpuset);
945 if (r < 0)
946 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
947
948 return bus_append_byte_array(m, field, cpuset, CPU_ALLOC_SIZE(r));
949 }
950
951 if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
952 int whitelist = 1;
953 const char *p = eq;
954
955 if (*p == '~') {
956 whitelist = 0;
957 p++;
958 }
959
960 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
961 if (r < 0)
962 return bus_log_create_error(r);
963
964 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
965 if (r < 0)
966 return bus_log_create_error(r);
967
968 r = sd_bus_message_open_container(m, 'v', "(bas)");
969 if (r < 0)
970 return bus_log_create_error(r);
971
972 r = sd_bus_message_open_container(m, 'r', "bas");
973 if (r < 0)
974 return bus_log_create_error(r);
975
976 r = sd_bus_message_append_basic(m, 'b', &whitelist);
977 if (r < 0)
978 return bus_log_create_error(r);
979
980 r = sd_bus_message_open_container(m, 'a', "s");
981 if (r < 0)
982 return bus_log_create_error(r);
983
984 for (p = eq;;) {
985 _cleanup_free_ char *word = NULL;
986
987 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
988 if (r == 0)
989 break;
990 if (r == -ENOMEM)
991 return log_oom();
992 if (r < 0)
993 return log_error_errno(r, "Invalid syntax: %s", eq);
994
995 r = sd_bus_message_append_basic(m, 's', word);
996 if (r < 0)
997 return bus_log_create_error(r);
998 }
999
1000 r = sd_bus_message_close_container(m);
1001 if (r < 0)
1002 return bus_log_create_error(r);
1003
1004 r = sd_bus_message_close_container(m);
1005 if (r < 0)
1006 return bus_log_create_error(r);
1007
1008 r = sd_bus_message_close_container(m);
1009 if (r < 0)
1010 return bus_log_create_error(r);
1011
1012 r = sd_bus_message_close_container(m);
1013 if (r < 0)
1014 return bus_log_create_error(r);
1015
1016 return 1;
1017 }
1018
1019 if (streq(field, "RestrictNamespaces")) {
1020 bool invert = false;
1021 unsigned long flags = 0;
1022
1023 if (eq[0] == '~') {
1024 invert = true;
1025 eq++;
1026 }
1027
1028 r = parse_boolean(eq);
1029 if (r > 0)
1030 flags = 0;
1031 else if (r == 0)
1032 flags = NAMESPACE_FLAGS_ALL;
1033 else {
1034 r = namespace_flag_from_string_many(eq, &flags);
1035 if (r < 0)
1036 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1037 }
1038
1039 if (invert)
1040 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1041
1042 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1043 if (r < 0)
1044 return bus_log_create_error(r);
1045
1046 return 1;
1047 }
1048
1049 if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) {
1050 const char *p = eq;
1051
1052 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1053 if (r < 0)
1054 return bus_log_create_error(r);
1055
1056 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1057 if (r < 0)
1058 return bus_log_create_error(r);
1059
1060 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1061 if (r < 0)
1062 return bus_log_create_error(r);
1063
1064 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1065 if (r < 0)
1066 return bus_log_create_error(r);
1067
1068 for (;;) {
1069 _cleanup_free_ char *source = NULL, *destination = NULL;
1070 char *s = NULL, *d = NULL;
1071 bool ignore_enoent = false;
1072 uint64_t flags = MS_REC;
1073
1074 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1075 if (r < 0)
1076 return log_error_errno(r, "Failed to parse argument: %m");
1077 if (r == 0)
1078 break;
1079
1080 s = source;
1081 if (s[0] == '-') {
1082 ignore_enoent = true;
1083 s++;
1084 }
1085
1086 if (p && p[-1] == ':') {
1087 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1088 if (r < 0)
1089 return log_error_errno(r, "Failed to parse argument: %m");
1090 if (r == 0) {
1091 log_error("Missing argument after ':': %s", eq);
1092 return -EINVAL;
1093 }
1094
1095 d = destination;
1096
1097 if (p && p[-1] == ':') {
1098 _cleanup_free_ char *options = NULL;
1099
1100 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
1101 if (r < 0)
1102 return log_error_errno(r, "Failed to parse argument: %m");
1103
1104 if (isempty(options) || streq(options, "rbind"))
1105 flags = MS_REC;
1106 else if (streq(options, "norbind"))
1107 flags = 0;
1108 else {
1109 log_error("Unknown options: %s", eq);
1110 return -EINVAL;
1111 }
1112 }
1113 } else
1114 d = s;
1115
1116
1117 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1118 if (r < 0)
1119 return bus_log_create_error(r);
1120 }
1121
1122 r = sd_bus_message_close_container(m);
1123 if (r < 0)
1124 return bus_log_create_error(r);
1125
1126 r = sd_bus_message_close_container(m);
1127 if (r < 0)
1128 return bus_log_create_error(r);
1129
1130 r = sd_bus_message_close_container(m);
1131 if (r < 0)
1132 return bus_log_create_error(r);
1133
1134 return 1;
1135 }
1136
1137 return 0;
1138 }
1139
1140 static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
1141
1142 if (streq(field, "KillMode"))
1143
1144 return bus_append_string(m, field, eq);
1145
1146 if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
1147
1148 return bus_append_parse_boolean(m, field, eq);
1149
1150 if (streq(field, "KillSignal"))
1151
1152 return bus_append_signal_from_string_try_harder(m, field, eq);
1153
1154 return 0;
1155 }
1156
1157 static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1158
1159 if (STR_IN_SET(field,
1160 "PathExists", "PathExistsGlob", "PathChanged",
1161 "PathModified", "DirectoryNotEmpty"))
1162
1163 return bus_append_string(m, field, eq);
1164
1165 if (streq(field, "MakeDirectory"))
1166
1167 return bus_append_parse_boolean(m, field, eq);
1168
1169 if (streq(field, "DirectoryMode"))
1170
1171 return bus_append_parse_mode(m, field, eq);
1172
1173 return 0;
1174 }
1175
1176 static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
1177
1178 if (STR_IN_SET(field, "Type", "Restart", "NotifyAccess"))
1179
1180 return bus_append_string(m, field, eq);
1181
1182 if (streq(field, "RemainAfterExit"))
1183
1184 return bus_append_parse_boolean(m, field, eq);
1185
1186 if (streq(field, "RuntimeMaxSec"))
1187
1188 return bus_append_parse_sec_rename(m, field, eq);
1189
1190 if (streq(field, "FileDescriptorStoreMax"))
1191
1192 return bus_append_safe_atou(m, field, eq);
1193
1194 if (STR_IN_SET(field,
1195 "ExecStartPre", "ExecStart", "ExecStartPost",
1196 "ExecReload", "ExecStop", "ExecStopPost"))
1197
1198 return bus_append_exec_command(m, field, eq);
1199
1200 return 0;
1201 }
1202
1203 static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1204 int r;
1205
1206 if (STR_IN_SET(field,
1207 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1208 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1209
1210 return bus_append_parse_boolean(m, field, eq);
1211
1212 if (STR_IN_SET(field, "Priority", "IPTTL", "Mark"))
1213
1214 return bus_append_safe_atoi(m, field, eq);
1215
1216 if (streq(field, "IPTOS"))
1217
1218 return bus_append_ip_tos_from_string(m, field, eq);
1219
1220 if (STR_IN_SET(field, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1221
1222 return bus_append_safe_atou(m, field, eq);
1223
1224 if (STR_IN_SET(field, "SocketMode", "DirectoryMode"))
1225
1226 return bus_append_parse_mode(m, field, eq);
1227
1228 if (STR_IN_SET(field, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1229
1230 return bus_append_safe_atoi64(m, field, eq);
1231
1232 if (STR_IN_SET(field, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1233
1234 return bus_append_parse_sec_rename(m, field, eq);
1235
1236 if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1237
1238 return bus_append_parse_size(m, field, eq, 1024);
1239
1240 if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1241
1242 return bus_append_exec_command(m, field, eq);
1243
1244 if (STR_IN_SET(field,
1245 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1246 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1247 "SocketUser", "SocketGroup"))
1248
1249 return bus_append_string(m, field, eq);
1250
1251 if (streq(field, "Symlinks"))
1252
1253 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1254
1255 if (streq(field, "SocketProtocol"))
1256
1257 return bus_append_socket_protocol_from_name(m, field, eq);
1258
1259 if (STR_IN_SET(field,
1260 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1261 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1262
1263 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + strlen("Listen"), eq);
1264 if (r < 0)
1265 return bus_log_create_error(r);
1266
1267 return 1;
1268 }
1269
1270 return 0;
1271 }
1272 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
1273
1274 if (streq(field, "OnCalendar"))
1275
1276 return bus_append_string(m, field, eq);
1277
1278 if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent"))
1279
1280 return bus_append_parse_boolean(m, field, eq);
1281
1282 if (STR_IN_SET(field,
1283 "OnActiveSec", "OnBootSec", "OnStartupSec",
1284 "OnUnitActiveSec","OnUnitInactiveSec"))
1285
1286 return bus_append_parse_sec(m, field, eq);
1287
1288 if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec"))
1289
1290 return bus_append_parse_sec_rename(m, field, eq);
1291
1292 return 0;
1293 }
1294
1295 static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
1296
1297 if (STR_IN_SET(field, "Description", "CollectMode", "FailureAction", "SuccessAction"))
1298
1299 return bus_append_string(m, field, eq);
1300
1301 if (streq(field, "DefaultDependencies"))
1302
1303 return bus_append_parse_boolean(m, field, eq);
1304
1305 if (unit_dependency_from_string(field) >= 0)
1306
1307 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1308
1309 return 0;
1310 }
1311
1312 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1313 const char *eq, *field;
1314 int r;
1315
1316 assert(m);
1317 assert(assignment);
1318
1319 eq = strchr(assignment, '=');
1320 if (!eq) {
1321 log_error("Not an assignment: %s", assignment);
1322 return -EINVAL;
1323 }
1324
1325 field = strndupa(assignment, eq - assignment);
1326 eq++;
1327
1328 switch (t) {
1329 case UNIT_SERVICE:
1330 r = bus_append_cgroup_property(m, field, eq);
1331 if (r != 0)
1332 return r;
1333
1334 r = bus_append_execute_property(m, field, eq);
1335 if (r != 0)
1336 return r;
1337
1338 r = bus_append_kill_property(m, field, eq);
1339 if (r != 0)
1340 return r;
1341
1342 r = bus_append_service_property(m, field, eq);
1343 if (r != 0)
1344 return r;
1345 break;
1346
1347 case UNIT_SOCKET:
1348 r = bus_append_cgroup_property(m, field, eq);
1349 if (r != 0)
1350 return r;
1351
1352 r = bus_append_execute_property(m, field, eq);
1353 if (r != 0)
1354 return r;
1355
1356 r = bus_append_kill_property(m, field, eq);
1357 if (r != 0)
1358 return r;
1359
1360 r = bus_append_socket_property(m, field, eq);
1361 if (r != 0)
1362 return r;
1363 break;
1364
1365 case UNIT_TIMER:
1366 r = bus_append_timer_property(m, field, eq);
1367 if (r != 0)
1368 return r;
1369 break;
1370
1371 case UNIT_PATH:
1372 r = bus_append_path_property(m, field, eq);
1373 if (r != 0)
1374 return r;
1375 break;
1376
1377 case UNIT_SLICE:
1378 r = bus_append_cgroup_property(m, field, eq);
1379 if (r != 0)
1380 return r;
1381 break;
1382
1383 case UNIT_SCOPE:
1384 r = bus_append_cgroup_property(m, field, eq);
1385 if (r != 0)
1386 return r;
1387
1388 r = bus_append_kill_property(m, field, eq);
1389 if (r != 0)
1390 return r;
1391 break;
1392
1393 case UNIT_MOUNT:
1394 case UNIT_AUTOMOUNT:
1395 break;
1396
1397 case UNIT_TARGET:
1398 case UNIT_DEVICE:
1399 case UNIT_SWAP:
1400 log_error("Not supported unit type");
1401 return -EINVAL;
1402
1403 default:
1404 log_error("Invalid unit type");
1405 return -EINVAL;
1406 }
1407
1408 r = bus_append_unit_property(m, field, eq);
1409 if (r != 0)
1410 return r;
1411
1412 log_error("Unknown assignment: %s", assignment);
1413 return -EINVAL;
1414 }
1415
1416 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
1417 char **i;
1418 int r;
1419
1420 assert(m);
1421
1422 STRV_FOREACH(i, l) {
1423 r = bus_append_unit_property_assignment(m, t, *i);
1424 if (r < 0)
1425 return r;
1426 }
1427
1428 return 0;
1429 }
1430
1431 typedef struct BusWaitForJobs {
1432 sd_bus *bus;
1433 Set *jobs;
1434
1435 char *name;
1436 char *result;
1437
1438 sd_bus_slot *slot_job_removed;
1439 sd_bus_slot *slot_disconnected;
1440 } BusWaitForJobs;
1441
1442 static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1443 assert(m);
1444
1445 log_error("Warning! D-Bus connection terminated.");
1446 sd_bus_close(sd_bus_message_get_bus(m));
1447
1448 return 0;
1449 }
1450
1451 static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1452 const char *path, *unit, *result;
1453 BusWaitForJobs *d = userdata;
1454 uint32_t id;
1455 char *found;
1456 int r;
1457
1458 assert(m);
1459 assert(d);
1460
1461 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
1462 if (r < 0) {
1463 bus_log_parse_error(r);
1464 return 0;
1465 }
1466
1467 found = set_remove(d->jobs, (char*) path);
1468 if (!found)
1469 return 0;
1470
1471 free(found);
1472
1473 if (!isempty(result))
1474 d->result = strdup(result);
1475
1476 if (!isempty(unit))
1477 d->name = strdup(unit);
1478
1479 return 0;
1480 }
1481
1482 void bus_wait_for_jobs_free(BusWaitForJobs *d) {
1483 if (!d)
1484 return;
1485
1486 set_free_free(d->jobs);
1487
1488 sd_bus_slot_unref(d->slot_disconnected);
1489 sd_bus_slot_unref(d->slot_job_removed);
1490
1491 sd_bus_unref(d->bus);
1492
1493 free(d->name);
1494 free(d->result);
1495
1496 free(d);
1497 }
1498
1499 int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
1500 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
1501 int r;
1502
1503 assert(bus);
1504 assert(ret);
1505
1506 d = new0(BusWaitForJobs, 1);
1507 if (!d)
1508 return -ENOMEM;
1509
1510 d->bus = sd_bus_ref(bus);
1511
1512 /* When we are a bus client we match by sender. Direct
1513 * connections OTOH have no initialized sender field, and
1514 * hence we ignore the sender then */
1515 r = sd_bus_add_match(
1516 bus,
1517 &d->slot_job_removed,
1518 bus->bus_client ?
1519 "type='signal',"
1520 "sender='org.freedesktop.systemd1',"
1521 "interface='org.freedesktop.systemd1.Manager',"
1522 "member='JobRemoved',"
1523 "path='/org/freedesktop/systemd1'" :
1524 "type='signal',"
1525 "interface='org.freedesktop.systemd1.Manager',"
1526 "member='JobRemoved',"
1527 "path='/org/freedesktop/systemd1'",
1528 match_job_removed, d);
1529 if (r < 0)
1530 return r;
1531
1532 r = sd_bus_add_match(
1533 bus,
1534 &d->slot_disconnected,
1535 "type='signal',"
1536 "sender='org.freedesktop.DBus.Local',"
1537 "interface='org.freedesktop.DBus.Local',"
1538 "member='Disconnected'",
1539 match_disconnected, d);
1540 if (r < 0)
1541 return r;
1542
1543 *ret = d;
1544 d = NULL;
1545
1546 return 0;
1547 }
1548
1549 static int bus_process_wait(sd_bus *bus) {
1550 int r;
1551
1552 for (;;) {
1553 r = sd_bus_process(bus, NULL);
1554 if (r < 0)
1555 return r;
1556 if (r > 0)
1557 return 0;
1558
1559 r = sd_bus_wait(bus, (uint64_t) -1);
1560 if (r < 0)
1561 return r;
1562 }
1563 }
1564
1565 static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
1566 _cleanup_free_ char *dbus_path = NULL;
1567
1568 assert(d);
1569 assert(d->name);
1570 assert(result);
1571
1572 if (!endswith(d->name, ".service"))
1573 return -EINVAL;
1574
1575 dbus_path = unit_dbus_path_from_name(d->name);
1576 if (!dbus_path)
1577 return -ENOMEM;
1578
1579 return sd_bus_get_property_string(d->bus,
1580 "org.freedesktop.systemd1",
1581 dbus_path,
1582 "org.freedesktop.systemd1.Service",
1583 "Result",
1584 NULL,
1585 result);
1586 }
1587
1588 static const struct {
1589 const char *result, *explanation;
1590 } explanations [] = {
1591 { "resources", "of unavailable resources or another system error" },
1592 { "protocol", "the service did not take the steps required by its unit configuration" },
1593 { "timeout", "a timeout was exceeded" },
1594 { "exit-code", "the control process exited with error code" },
1595 { "signal", "a fatal signal was delivered to the control process" },
1596 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1597 { "watchdog", "the service failed to send watchdog ping" },
1598 { "start-limit", "start of the service was attempted too often" }
1599 };
1600
1601 static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
1602 _cleanup_free_ char *service_shell_quoted = NULL;
1603 const char *systemctl = "systemctl", *journalctl = "journalctl";
1604
1605 assert(service);
1606
1607 service_shell_quoted = shell_maybe_quote(service, ESCAPE_BACKSLASH);
1608
1609 if (!strv_isempty((char**) extra_args)) {
1610 _cleanup_free_ char *t;
1611
1612 t = strv_join((char**) extra_args, " ");
1613 systemctl = strjoina("systemctl ", t ? : "<args>");
1614 journalctl = strjoina("journalctl ", t ? : "<args>");
1615 }
1616
1617 if (!isempty(result)) {
1618 unsigned i;
1619
1620 for (i = 0; i < ELEMENTSOF(explanations); ++i)
1621 if (streq(result, explanations[i].result))
1622 break;
1623
1624 if (i < ELEMENTSOF(explanations)) {
1625 log_error("Job for %s failed because %s.\n"
1626 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1627 service,
1628 explanations[i].explanation,
1629 systemctl,
1630 service_shell_quoted ?: "<service>",
1631 journalctl);
1632 goto finish;
1633 }
1634 }
1635
1636 log_error("Job for %s failed.\n"
1637 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1638 service,
1639 systemctl,
1640 service_shell_quoted ?: "<service>",
1641 journalctl);
1642
1643 finish:
1644 /* For some results maybe additional explanation is required */
1645 if (streq_ptr(result, "start-limit"))
1646 log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
1647 "followed by \"%1$s start %2$s\" again.",
1648 systemctl,
1649 service_shell_quoted ?: "<service>");
1650 }
1651
1652 static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
1653 int r = 0;
1654
1655 assert(d->result);
1656
1657 if (!quiet) {
1658 if (streq(d->result, "canceled"))
1659 log_error("Job for %s canceled.", strna(d->name));
1660 else if (streq(d->result, "timeout"))
1661 log_error("Job for %s timed out.", strna(d->name));
1662 else if (streq(d->result, "dependency"))
1663 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
1664 else if (streq(d->result, "invalid"))
1665 log_error("%s is not active, cannot reload.", strna(d->name));
1666 else if (streq(d->result, "assert"))
1667 log_error("Assertion failed on job for %s.", strna(d->name));
1668 else if (streq(d->result, "unsupported"))
1669 log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
1670 else if (streq(d->result, "collected"))
1671 log_error("Queued job for %s was garbage collected.", strna(d->name));
1672 else if (!STR_IN_SET(d->result, "done", "skipped")) {
1673 if (d->name) {
1674 _cleanup_free_ char *result = NULL;
1675 int q;
1676
1677 q = bus_job_get_service_result(d, &result);
1678 if (q < 0)
1679 log_debug_errno(q, "Failed to get Result property of unit %s: %m", d->name);
1680
1681 log_job_error_with_service_result(d->name, result, extra_args);
1682 } else
1683 log_error("Job failed. See \"journalctl -xe\" for details.");
1684 }
1685 }
1686
1687 if (STR_IN_SET(d->result, "canceled", "collected"))
1688 r = -ECANCELED;
1689 else if (streq(d->result, "timeout"))
1690 r = -ETIME;
1691 else if (streq(d->result, "dependency"))
1692 r = -EIO;
1693 else if (streq(d->result, "invalid"))
1694 r = -ENOEXEC;
1695 else if (streq(d->result, "assert"))
1696 r = -EPROTO;
1697 else if (streq(d->result, "unsupported"))
1698 r = -EOPNOTSUPP;
1699 else if (!STR_IN_SET(d->result, "done", "skipped"))
1700 r = -EIO;
1701
1702 return r;
1703 }
1704
1705 int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
1706 int r = 0;
1707
1708 assert(d);
1709
1710 while (!set_isempty(d->jobs)) {
1711 int q;
1712
1713 q = bus_process_wait(d->bus);
1714 if (q < 0)
1715 return log_error_errno(q, "Failed to wait for response: %m");
1716
1717 if (d->result) {
1718 q = check_wait_response(d, quiet, extra_args);
1719 /* Return the first error as it is most likely to be
1720 * meaningful. */
1721 if (q < 0 && r == 0)
1722 r = q;
1723
1724 log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
1725 }
1726
1727 d->name = mfree(d->name);
1728 d->result = mfree(d->result);
1729 }
1730
1731 return r;
1732 }
1733
1734 int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
1735 int r;
1736
1737 assert(d);
1738
1739 r = set_ensure_allocated(&d->jobs, &string_hash_ops);
1740 if (r < 0)
1741 return r;
1742
1743 return set_put_strdup(d->jobs, path);
1744 }
1745
1746 int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
1747 int r;
1748
1749 r = bus_wait_for_jobs_add(d, path);
1750 if (r < 0)
1751 return log_oom();
1752
1753 return bus_wait_for_jobs(d, quiet, NULL);
1754 }
1755
1756 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
1757 const char *type, *path, *source;
1758 int r;
1759
1760 /* changes is dereferenced when calling unit_file_dump_changes() later,
1761 * so we have to make sure this is not NULL. */
1762 assert(changes);
1763 assert(n_changes);
1764
1765 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1766 if (r < 0)
1767 return bus_log_parse_error(r);
1768
1769 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1770 /* We expect only "success" changes to be sent over the bus.
1771 Hence, reject anything negative. */
1772 UnitFileChangeType ch = unit_file_change_type_from_string(type);
1773
1774 if (ch < 0) {
1775 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
1776 continue;
1777 }
1778
1779 r = unit_file_changes_add(changes, n_changes, ch, path, source);
1780 if (r < 0)
1781 return r;
1782 }
1783 if (r < 0)
1784 return bus_log_parse_error(r);
1785
1786 r = sd_bus_message_exit_container(m);
1787 if (r < 0)
1788 return bus_log_parse_error(r);
1789
1790 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
1791 return 0;
1792 }
1793
1794 struct CGroupInfo {
1795 char *cgroup_path;
1796 bool is_const; /* If false, cgroup_path should be free()'d */
1797
1798 Hashmap *pids; /* PID → process name */
1799 bool done;
1800
1801 struct CGroupInfo *parent;
1802 LIST_FIELDS(struct CGroupInfo, siblings);
1803 LIST_HEAD(struct CGroupInfo, children);
1804 size_t n_children;
1805 };
1806
1807 static bool IS_ROOT(const char *p) {
1808 return isempty(p) || streq(p, "/");
1809 }
1810
1811 static int add_cgroup(Hashmap *cgroups, const char *path, bool is_const, struct CGroupInfo **ret) {
1812 struct CGroupInfo *parent = NULL, *cg;
1813 int r;
1814
1815 assert(cgroups);
1816 assert(ret);
1817
1818 if (IS_ROOT(path))
1819 path = "/";
1820
1821 cg = hashmap_get(cgroups, path);
1822 if (cg) {
1823 *ret = cg;
1824 return 0;
1825 }
1826
1827 if (!IS_ROOT(path)) {
1828 const char *e, *pp;
1829
1830 e = strrchr(path, '/');
1831 if (!e)
1832 return -EINVAL;
1833
1834 pp = strndupa(path, e - path);
1835 if (!pp)
1836 return -ENOMEM;
1837
1838 r = add_cgroup(cgroups, pp, false, &parent);
1839 if (r < 0)
1840 return r;
1841 }
1842
1843 cg = new0(struct CGroupInfo, 1);
1844 if (!cg)
1845 return -ENOMEM;
1846
1847 if (is_const)
1848 cg->cgroup_path = (char*) path;
1849 else {
1850 cg->cgroup_path = strdup(path);
1851 if (!cg->cgroup_path) {
1852 free(cg);
1853 return -ENOMEM;
1854 }
1855 }
1856
1857 cg->is_const = is_const;
1858 cg->parent = parent;
1859
1860 r = hashmap_put(cgroups, cg->cgroup_path, cg);
1861 if (r < 0) {
1862 if (!is_const)
1863 free(cg->cgroup_path);
1864 free(cg);
1865 return r;
1866 }
1867
1868 if (parent) {
1869 LIST_PREPEND(siblings, parent->children, cg);
1870 parent->n_children++;
1871 }
1872
1873 *ret = cg;
1874 return 1;
1875 }
1876
1877 static int add_process(
1878 Hashmap *cgroups,
1879 const char *path,
1880 pid_t pid,
1881 const char *name) {
1882
1883 struct CGroupInfo *cg;
1884 int r;
1885
1886 assert(cgroups);
1887 assert(name);
1888 assert(pid > 0);
1889
1890 r = add_cgroup(cgroups, path, true, &cg);
1891 if (r < 0)
1892 return r;
1893
1894 r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops);
1895 if (r < 0)
1896 return r;
1897
1898 return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name);
1899 }
1900
1901 static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) {
1902 assert(cgroups);
1903 assert(cg);
1904
1905 while (cg->children)
1906 remove_cgroup(cgroups, cg->children);
1907
1908 hashmap_remove(cgroups, cg->cgroup_path);
1909
1910 if (!cg->is_const)
1911 free(cg->cgroup_path);
1912
1913 hashmap_free(cg->pids);
1914
1915 if (cg->parent)
1916 LIST_REMOVE(siblings, cg->parent->children, cg);
1917
1918 free(cg);
1919 }
1920
1921 static int cgroup_info_compare_func(const void *a, const void *b) {
1922 const struct CGroupInfo *x = *(const struct CGroupInfo* const*) a, *y = *(const struct CGroupInfo* const*) b;
1923
1924 assert(x);
1925 assert(y);
1926
1927 return strcmp(x->cgroup_path, y->cgroup_path);
1928 }
1929
1930 static int dump_processes(
1931 Hashmap *cgroups,
1932 const char *cgroup_path,
1933 const char *prefix,
1934 unsigned n_columns,
1935 OutputFlags flags) {
1936
1937 struct CGroupInfo *cg;
1938 int r;
1939
1940 assert(prefix);
1941
1942 if (IS_ROOT(cgroup_path))
1943 cgroup_path = "/";
1944
1945 cg = hashmap_get(cgroups, cgroup_path);
1946 if (!cg)
1947 return 0;
1948
1949 if (!hashmap_isempty(cg->pids)) {
1950 const char *name;
1951 size_t n = 0, i;
1952 pid_t *pids;
1953 void *pidp;
1954 Iterator j;
1955 int width;
1956
1957 /* Order processes by their PID */
1958 pids = newa(pid_t, hashmap_size(cg->pids));
1959
1960 HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j)
1961 pids[n++] = PTR_TO_PID(pidp);
1962
1963 assert(n == hashmap_size(cg->pids));
1964 qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
1965
1966 width = DECIMAL_STR_WIDTH(pids[n-1]);
1967
1968 for (i = 0; i < n; i++) {
1969 _cleanup_free_ char *e = NULL;
1970 const char *special;
1971 bool more;
1972
1973 name = hashmap_get(cg->pids, PID_TO_PTR(pids[i]));
1974 assert(name);
1975
1976 if (n_columns != 0) {
1977 unsigned k;
1978
1979 k = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
1980
1981 e = ellipsize(name, k, 100);
1982 if (e)
1983 name = e;
1984 }
1985
1986 more = i+1 < n || cg->children;
1987 special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT);
1988
1989 fprintf(stdout, "%s%s%*"PID_PRI" %s\n",
1990 prefix,
1991 special,
1992 width, pids[i],
1993 name);
1994 }
1995 }
1996
1997 if (cg->children) {
1998 struct CGroupInfo **children, *child;
1999 size_t n = 0, i;
2000
2001 /* Order subcgroups by their name */
2002 children = newa(struct CGroupInfo*, cg->n_children);
2003 LIST_FOREACH(siblings, child, cg->children)
2004 children[n++] = child;
2005 assert(n == cg->n_children);
2006 qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func);
2007
2008 if (n_columns != 0)
2009 n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
2010
2011 for (i = 0; i < n; i++) {
2012 _cleanup_free_ char *pp = NULL;
2013 const char *name, *special;
2014 bool more;
2015
2016 child = children[i];
2017
2018 name = strrchr(child->cgroup_path, '/');
2019 if (!name)
2020 return -EINVAL;
2021 name++;
2022
2023 more = i+1 < n;
2024 special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT);
2025
2026 fputs(prefix, stdout);
2027 fputs(special, stdout);
2028 fputs(name, stdout);
2029 fputc('\n', stdout);
2030
2031 special = special_glyph(more ? TREE_VERTICAL : TREE_SPACE);
2032
2033 pp = strappend(prefix, special);
2034 if (!pp)
2035 return -ENOMEM;
2036
2037 r = dump_processes(cgroups, child->cgroup_path, pp, n_columns, flags);
2038 if (r < 0)
2039 return r;
2040 }
2041 }
2042
2043 cg->done = true;
2044 return 0;
2045 }
2046
2047 static int dump_extra_processes(
2048 Hashmap *cgroups,
2049 const char *prefix,
2050 unsigned n_columns,
2051 OutputFlags flags) {
2052
2053 _cleanup_free_ pid_t *pids = NULL;
2054 _cleanup_hashmap_free_ Hashmap *names = NULL;
2055 struct CGroupInfo *cg;
2056 size_t n_allocated = 0, n = 0, k;
2057 Iterator i;
2058 int width, r;
2059
2060 /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
2061 * combined, sorted, linear list. */
2062
2063 HASHMAP_FOREACH(cg, cgroups, i) {
2064 const char *name;
2065 void *pidp;
2066 Iterator j;
2067
2068 if (cg->done)
2069 continue;
2070
2071 if (hashmap_isempty(cg->pids))
2072 continue;
2073
2074 r = hashmap_ensure_allocated(&names, &trivial_hash_ops);
2075 if (r < 0)
2076 return r;
2077
2078 if (!GREEDY_REALLOC(pids, n_allocated, n + hashmap_size(cg->pids)))
2079 return -ENOMEM;
2080
2081 HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) {
2082 pids[n++] = PTR_TO_PID(pidp);
2083
2084 r = hashmap_put(names, pidp, (void*) name);
2085 if (r < 0)
2086 return r;
2087 }
2088 }
2089
2090 if (n == 0)
2091 return 0;
2092
2093 qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
2094 width = DECIMAL_STR_WIDTH(pids[n-1]);
2095
2096 for (k = 0; k < n; k++) {
2097 _cleanup_free_ char *e = NULL;
2098 const char *name;
2099
2100 name = hashmap_get(names, PID_TO_PTR(pids[k]));
2101 assert(name);
2102
2103 if (n_columns != 0) {
2104 unsigned z;
2105
2106 z = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
2107
2108 e = ellipsize(name, z, 100);
2109 if (e)
2110 name = e;
2111 }
2112
2113 fprintf(stdout, "%s%s %*" PID_PRI " %s\n",
2114 prefix,
2115 special_glyph(TRIANGULAR_BULLET),
2116 width, pids[k],
2117 name);
2118 }
2119
2120 return 0;
2121 }
2122
2123 int unit_show_processes(
2124 sd_bus *bus,
2125 const char *unit,
2126 const char *cgroup_path,
2127 const char *prefix,
2128 unsigned n_columns,
2129 OutputFlags flags,
2130 sd_bus_error *error) {
2131
2132 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2133 Hashmap *cgroups = NULL;
2134 struct CGroupInfo *cg;
2135 int r;
2136
2137 assert(bus);
2138 assert(unit);
2139
2140 if (flags & OUTPUT_FULL_WIDTH)
2141 n_columns = 0;
2142 else if (n_columns <= 0)
2143 n_columns = columns();
2144
2145 prefix = strempty(prefix);
2146
2147 r = sd_bus_call_method(
2148 bus,
2149 "org.freedesktop.systemd1",
2150 "/org/freedesktop/systemd1",
2151 "org.freedesktop.systemd1.Manager",
2152 "GetUnitProcesses",
2153 error,
2154 &reply,
2155 "s",
2156 unit);
2157 if (r < 0)
2158 return r;
2159
2160 cgroups = hashmap_new(&string_hash_ops);
2161 if (!cgroups)
2162 return -ENOMEM;
2163
2164 r = sd_bus_message_enter_container(reply, 'a', "(sus)");
2165 if (r < 0)
2166 goto finish;
2167
2168 for (;;) {
2169 const char *path = NULL, *name = NULL;
2170 uint32_t pid;
2171
2172 r = sd_bus_message_read(reply, "(sus)", &path, &pid, &name);
2173 if (r < 0)
2174 goto finish;
2175 if (r == 0)
2176 break;
2177
2178 r = add_process(cgroups, path, pid, name);
2179 if (r < 0)
2180 goto finish;
2181 }
2182
2183 r = sd_bus_message_exit_container(reply);
2184 if (r < 0)
2185 goto finish;
2186
2187 r = dump_processes(cgroups, cgroup_path, prefix, n_columns, flags);
2188 if (r < 0)
2189 goto finish;
2190
2191 r = dump_extra_processes(cgroups, prefix, n_columns, flags);
2192
2193 finish:
2194 while ((cg = hashmap_first(cgroups)))
2195 remove_cgroup(cgroups, cg);
2196
2197 hashmap_free(cgroups);
2198
2199 return r;
2200 }