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