]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cgroup-show.c
bus: use bus_log_connect_error to print error message
[thirdparty/systemd.git] / src / shared / cgroup-show.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
ab35fb1b 2
fa776d8e
LP
3#include <dirent.h>
4#include <errno.h>
a8fbdf54 5#include <stddef.h>
07630cea 6#include <stdio.h>
a8fbdf54 7#include <stdlib.h>
ab35fb1b 8
b5efdb8a 9#include "alloc-util.h"
049cb73b
ZJS
10#include "bus-error.h"
11#include "bus-util.h"
3ffd4af2 12#include "cgroup-show.h"
07630cea 13#include "cgroup-util.h"
686d13b9 14#include "env-file.h"
3ffd4af2 15#include "fd-util.h"
f97b34a6 16#include "format-util.h"
8752c575 17#include "locale-util.h"
ab35fb1b 18#include "macro.h"
a8fbdf54 19#include "output-mode.h"
74d8ccd4 20#include "parse-util.h"
9eb977db 21#include "path-util.h"
07630cea 22#include "process-util.h"
760877e9 23#include "sort-util.h"
07630cea 24#include "string-util.h"
288a74cc 25#include "terminal-util.h"
049cb73b 26#include "unit-name.h"
74d8ccd4 27#include "xattr-util.h"
ab35fb1b 28
0ff308c8
LP
29static void show_pid_array(
30 pid_t pids[],
31 unsigned n_pids,
32 const char *prefix,
bc28751e 33 size_t n_columns,
0ff308c8
LP
34 bool extra,
35 bool more,
36 OutputFlags flags) {
37
3da7a50f 38 unsigned i, j, pid_width;
b69d29ce 39
da41abc5 40 if (n_pids == 0)
3637713a
LP
41 return;
42
93bab288 43 typesafe_qsort(pids, n_pids, pid_compare_func);
b69d29ce 44
3da7a50f
ZJS
45 /* Filter duplicates */
46 for (j = 0, i = 1; i < n_pids; i++) {
47 if (pids[i] == pids[j])
48 continue;
49 pids[++j] = pids[i];
b69d29ce 50 }
3da7a50f
ZJS
51 n_pids = j + 1;
52 pid_width = DECIMAL_STR_WIDTH(pids[j]);
b69d29ce 53
b47d419c 54 if (flags & OUTPUT_FULL_WIDTH)
bc28751e 55 n_columns = SIZE_MAX;
9bdbc2e2 56 else {
31c294dc
ZJS
57 if (n_columns > pid_width + 3) /* something like "├─1114784 " */
58 n_columns -= pid_width + 3;
9bdbc2e2
LN
59 else
60 n_columns = 20;
61 }
b69d29ce 62 for (i = 0; i < n_pids; i++) {
b47d419c 63 _cleanup_free_ char *t = NULL;
b69d29ce 64
e3b4efd2
ZJS
65 (void) get_process_cmdline(pids[i], n_columns,
66 PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_USE_LOCALE,
67 &t);
b69d29ce 68
6b01f1d3 69 if (extra)
9a6f746f 70 printf("%s%s ", prefix, special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET));
6b01f1d3 71 else
9a6f746f 72 printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT)));
6b01f1d3 73
a2e361dc 74 printf("%s%*"PID_PRI" %s%s\n", ansi_grey(), pid_width, pids[i], strna(t), ansi_normal());
b69d29ce
LP
75 }
76}
77
291d565a
LP
78static int show_cgroup_one_by_path(
79 const char *path,
80 const char *prefix,
bc28751e 81 size_t n_columns,
291d565a 82 bool more,
291d565a 83 OutputFlags flags) {
b69d29ce 84
ab35fb1b 85 char *fn;
7027ff61 86 _cleanup_fclose_ FILE *f = NULL;
ab35fb1b 87 size_t n = 0, n_allocated = 0;
7027ff61 88 _cleanup_free_ pid_t *pids = NULL;
b47d419c 89 _cleanup_free_ char *p = NULL;
b69d29ce 90 pid_t pid;
fa776d8e 91 int r;
ab35fb1b 92
7027ff61 93 r = cg_mangle_path(path, &p);
b69d29ce 94 if (r < 0)
35d2e7ec 95 return r;
ab35fb1b 96
63c372cb 97 fn = strjoina(p, "/cgroup.procs");
fa776d8e 98 f = fopen(fn, "re");
ab35fb1b 99 if (!f)
fa776d8e 100 return -errno;
ab35fb1b 101
c6c18be3 102 while ((r = cg_read_pid(f, &pid)) > 0) {
ab35fb1b 103
0ff308c8 104 if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0)
1e5678d0
LP
105 continue;
106
3da7a50f
ZJS
107 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
108 return -ENOMEM;
ab35fb1b
LP
109
110 assert(n < n_allocated);
c6c18be3 111 pids[n++] = pid;
ab35fb1b
LP
112 }
113
c6c18be3 114 if (r < 0)
7027ff61 115 return r;
c6c18be3 116
0ff308c8 117 show_pid_array(pids, n, prefix, n_columns, false, more, flags);
ab35fb1b 118
7027ff61 119 return 0;
fa776d8e
LP
120}
121
74d8ccd4
LP
122static int show_cgroup_name(
123 const char *path,
124 const char *prefix,
125 const char *glyph) {
126
127 _cleanup_free_ char *b = NULL;
128 bool delegate = false;
129 int r;
130
131 r = getxattr_malloc(path, "trusted.delegate", &b, false);
132 if (r < 0) {
133 if (r != -ENODATA)
134 log_debug_errno(r, "Failed to read trusted.delegate extended attribute: %m");
135 } else {
136 r = parse_boolean(b);
137 if (r < 0)
138 log_debug_errno(r, "Failed to parse trusted.delegate extended attribute boolean value: %m");
139 else
140 delegate = r > 0;
141
142 b = mfree(b);
143 }
144
145 b = strdup(basename(path));
146 if (!b)
147 return -ENOMEM;
148
149 printf("%s%s%s%s%s %s%s%s\n",
150 prefix, glyph,
151 delegate ? ansi_underline() : "",
152 cg_unescape(b),
153 delegate ? ansi_normal() : "",
154 delegate ? ansi_highlight() : "",
155 delegate ? special_glyph(SPECIAL_GLYPH_ELLIPSIS) : "",
156 delegate ? ansi_normal() : "");
157 return 0;
158}
159
291d565a
LP
160int show_cgroup_by_path(
161 const char *path,
162 const char *prefix,
bc28751e 163 size_t n_columns,
291d565a
LP
164 OutputFlags flags) {
165
7027ff61
LP
166 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
167 _cleanup_closedir_ DIR *d = NULL;
fa776d8e 168 bool shown_pids = false;
74d8ccd4 169 char *gn = NULL;
fa776d8e
LP
170 int r;
171
b69d29ce
LP
172 assert(path);
173
fa776d8e
LP
174 if (n_columns <= 0)
175 n_columns = columns();
176
291d565a 177 prefix = strempty(prefix);
fa776d8e 178
7027ff61 179 r = cg_mangle_path(path, &fn);
c3175a7f 180 if (r < 0)
35d2e7ec 181 return r;
fa776d8e 182
c3175a7f 183 d = opendir(fn);
7027ff61 184 if (!d)
fa776d8e 185 return -errno;
fa776d8e 186
35d2e7ec 187 while ((r = cg_read_subgroup(d, &gn)) > 0) {
7027ff61 188 _cleanup_free_ char *k = NULL;
c3175a7f 189
657ee2d8 190 k = path_join(fn, gn);
c3175a7f 191 free(gn);
7027ff61
LP
192 if (!k)
193 return -ENOMEM;
c3175a7f 194
6f883237 195 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
c3175a7f 196 continue;
fa776d8e
LP
197
198 if (!shown_pids) {
0ff308c8 199 show_cgroup_one_by_path(path, prefix, n_columns, true, flags);
fa776d8e
LP
200 shown_pids = true;
201 }
202
203 if (last) {
74d8ccd4
LP
204 r = show_cgroup_name(last, prefix, special_glyph(SPECIAL_GLYPH_TREE_BRANCH));
205 if (r < 0)
206 return r;
fa776d8e 207
c3175a7f 208 if (!p1) {
b910cc72 209 p1 = strjoin(prefix, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL));
7027ff61
LP
210 if (!p1)
211 return -ENOMEM;
c3175a7f 212 }
fa776d8e 213
0ff308c8 214 show_cgroup_by_path(last, p1, n_columns-2, flags);
fa776d8e 215 free(last);
fa776d8e
LP
216 }
217
ae2a15bc 218 last = TAKE_PTR(k);
fa776d8e
LP
219 }
220
35d2e7ec 221 if (r < 0)
7027ff61 222 return r;
35d2e7ec 223
fa776d8e 224 if (!shown_pids)
0ff308c8 225 show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags);
fa776d8e
LP
226
227 if (last) {
74d8ccd4
LP
228 r = show_cgroup_name(last, prefix, special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
229 if (r < 0)
230 return r;
fa776d8e 231
c3175a7f 232 if (!p2) {
b910cc72 233 p2 = strjoin(prefix, " ");
7027ff61
LP
234 if (!p2)
235 return -ENOMEM;
c3175a7f 236 }
fa776d8e 237
0ff308c8 238 show_cgroup_by_path(last, p2, n_columns-2, flags);
fa776d8e
LP
239 }
240
7027ff61 241 return 0;
ab35fb1b 242}
35d2e7ec 243
291d565a
LP
244int show_cgroup(const char *controller,
245 const char *path,
246 const char *prefix,
bc28751e 247 size_t n_columns,
291d565a 248 OutputFlags flags) {
7027ff61 249 _cleanup_free_ char *p = NULL;
35d2e7ec
LP
250 int r;
251
35d2e7ec
LP
252 assert(path);
253
1e5678d0
LP
254 r = cg_get_path(controller, path, NULL, &p);
255 if (r < 0)
35d2e7ec
LP
256 return r;
257
0ff308c8 258 return show_cgroup_by_path(p, prefix, n_columns, flags);
35d2e7ec 259}
b69d29ce 260
291d565a
LP
261static int show_extra_pids(
262 const char *controller,
263 const char *path,
264 const char *prefix,
bc28751e 265 size_t n_columns,
291d565a
LP
266 const pid_t pids[],
267 unsigned n_pids,
268 OutputFlags flags) {
269
7fd1b19b 270 _cleanup_free_ pid_t *copy = NULL;
b69d29ce
LP
271 unsigned i, j;
272 int r;
273
b69d29ce
LP
274 assert(path);
275
276 if (n_pids <= 0)
277 return 0;
278
279 if (n_columns <= 0)
280 n_columns = columns();
281
7027ff61 282 prefix = strempty(prefix);
b69d29ce
LP
283
284 copy = new(pid_t, n_pids);
285 if (!copy)
286 return -ENOMEM;
287
288 for (i = 0, j = 0; i < n_pids; i++) {
7fd1b19b 289 _cleanup_free_ char *k = NULL;
b69d29ce 290
7027ff61 291 r = cg_pid_get_path(controller, pids[i], &k);
050fbdb8 292 if (r < 0)
b69d29ce 293 return r;
b69d29ce
LP
294
295 if (path_startswith(k, path))
296 continue;
297
298 copy[j++] = pids[i];
299 }
300
0ff308c8 301 show_pid_array(copy, j, prefix, n_columns, true, false, flags);
b69d29ce 302
b69d29ce
LP
303 return 0;
304}
305
291d565a
LP
306int show_cgroup_and_extra(
307 const char *controller,
308 const char *path,
309 const char *prefix,
bc28751e 310 size_t n_columns,
291d565a
LP
311 const pid_t extra_pids[],
312 unsigned n_extra_pids,
313 OutputFlags flags) {
314
b69d29ce
LP
315 int r;
316
b69d29ce
LP
317 assert(path);
318
0ff308c8 319 r = show_cgroup(controller, path, prefix, n_columns, flags);
b69d29ce
LP
320 if (r < 0)
321 return r;
322
9bdbc2e2 323 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
b69d29ce
LP
324}
325
bc06be75
ZJS
326int show_cgroup_get_unit_path_and_warn(
327 sd_bus *bus,
328 const char *unit,
329 char **ret) {
330
331 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
332 _cleanup_free_ char *path = NULL;
333 int r;
334
335 path = unit_dbus_path_from_name(unit);
336 if (!path)
337 return log_oom();
338
339 r = sd_bus_get_property_string(
340 bus,
341 "org.freedesktop.systemd1",
342 path,
343 unit_dbus_interface_from_name(unit),
344 "ControlGroup",
345 &error,
346 ret);
347 if (r < 0)
348 return log_error_errno(r, "Failed to query unit control group path: %s",
349 bus_error_message(&error, r));
350
351 return 0;
352}
353
d3e8277d 354int show_cgroup_get_path_and_warn(
049cb73b 355 const char *machine,
d3e8277d 356 const char *prefix,
049cb73b
ZJS
357 char **ret) {
358
049cb73b 359 int r;
d3e8277d
ZJS
360 _cleanup_free_ char *root = NULL;
361
362 if (machine) {
d3e8277d 363 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
bc06be75 364 _cleanup_free_ char *unit = NULL;
d3e8277d
ZJS
365 const char *m;
366
367 m = strjoina("/run/systemd/machines/", machine);
13df9c39 368 r = parse_env_file(NULL, m, "SCOPE", &unit);
d3e8277d
ZJS
369 if (r < 0)
370 return log_error_errno(r, "Failed to load machine data: %m");
049cb73b 371
d3e8277d
ZJS
372 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
373 if (r < 0)
ddbab78f 374 return bus_log_connect_error(r);
d3e8277d 375
bc06be75 376 r = show_cgroup_get_unit_path_and_warn(bus, unit, &root);
d3e8277d 377 if (r < 0)
bc06be75 378 return r;
d3e8277d
ZJS
379 } else {
380 r = cg_get_root_path(&root);
049cb73b
ZJS
381 if (r == -ENOMEDIUM)
382 return log_error_errno(r, "Failed to get root control group path.\n"
383 "No cgroup filesystem mounted on /sys/fs/cgroup");
384 else if (r < 0)
385 return log_error_errno(r, "Failed to get root control group path: %m");
049cb73b
ZJS
386 }
387
d3e8277d
ZJS
388 if (prefix) {
389 char *t;
049cb73b 390
d3e8277d
ZJS
391 t = strjoin(root, prefix);
392 if (!t)
393 return log_oom();
049cb73b 394
d3e8277d 395 *ret = t;
1cc6c93a
YW
396 } else
397 *ret = TAKE_PTR(root);
049cb73b
ZJS
398
399 return 0;
400}