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