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