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