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