]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cgroup-show.c
Merge pull request #12971 from yuwata/network-reassign-static-routes
[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
e3b4efd2
ZJS
64 (void) get_process_cmdline(pids[i], n_columns,
65 PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_USE_LOCALE,
66 &t);
b69d29ce 67
6b01f1d3 68 if (extra)
9a6f746f 69 printf("%s%s ", prefix, special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET));
6b01f1d3 70 else
9a6f746f 71 printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_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,
bc28751e 80 size_t n_columns,
291d565a 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,
bc28751e 124 size_t 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
657ee2d8 151 k = path_join(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) {
9a6f746f 165 printf("%s%s%s\n", prefix, special_glyph(SPECIAL_GLYPH_TREE_BRANCH), cg_unescape(basename(last)));
fa776d8e 166
c3175a7f 167 if (!p1) {
9a6f746f 168 p1 = strappend(prefix, special_glyph(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) {
9a6f746f 187 printf("%s%s%s\n", prefix, special_glyph(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,
bc28751e 204 size_t 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,
bc28751e 222 size_t n_columns,
291d565a
LP
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,
bc28751e 267 size_t 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
bc06be75
ZJS
283int show_cgroup_get_unit_path_and_warn(
284 sd_bus *bus,
285 const char *unit,
286 char **ret) {
287
288 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
289 _cleanup_free_ char *path = NULL;
290 int r;
291
292 path = unit_dbus_path_from_name(unit);
293 if (!path)
294 return log_oom();
295
296 r = sd_bus_get_property_string(
297 bus,
298 "org.freedesktop.systemd1",
299 path,
300 unit_dbus_interface_from_name(unit),
301 "ControlGroup",
302 &error,
303 ret);
304 if (r < 0)
305 return log_error_errno(r, "Failed to query unit control group path: %s",
306 bus_error_message(&error, r));
307
308 return 0;
309}
310
d3e8277d 311int show_cgroup_get_path_and_warn(
049cb73b 312 const char *machine,
d3e8277d 313 const char *prefix,
049cb73b
ZJS
314 char **ret) {
315
049cb73b 316 int r;
d3e8277d
ZJS
317 _cleanup_free_ char *root = NULL;
318
319 if (machine) {
d3e8277d 320 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
bc06be75 321 _cleanup_free_ char *unit = NULL;
d3e8277d
ZJS
322 const char *m;
323
324 m = strjoina("/run/systemd/machines/", machine);
13df9c39 325 r = parse_env_file(NULL, m, "SCOPE", &unit);
d3e8277d
ZJS
326 if (r < 0)
327 return log_error_errno(r, "Failed to load machine data: %m");
049cb73b 328
d3e8277d
ZJS
329 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
330 if (r < 0)
331 return log_error_errno(r, "Failed to create bus connection: %m");
332
bc06be75 333 r = show_cgroup_get_unit_path_and_warn(bus, unit, &root);
d3e8277d 334 if (r < 0)
bc06be75 335 return r;
d3e8277d
ZJS
336 } else {
337 r = cg_get_root_path(&root);
049cb73b
ZJS
338 if (r == -ENOMEDIUM)
339 return log_error_errno(r, "Failed to get root control group path.\n"
340 "No cgroup filesystem mounted on /sys/fs/cgroup");
341 else if (r < 0)
342 return log_error_errno(r, "Failed to get root control group path: %m");
049cb73b
ZJS
343 }
344
d3e8277d
ZJS
345 if (prefix) {
346 char *t;
049cb73b 347
d3e8277d
ZJS
348 t = strjoin(root, prefix);
349 if (!t)
350 return log_oom();
049cb73b 351
d3e8277d 352 *ret = t;
1cc6c93a
YW
353 } else
354 *ret = TAKE_PTR(root);
049cb73b
ZJS
355
356 return 0;
357}