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