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