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