]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
Merge pull request #5420 from OpenDZ/tixxdz/namespace-fixes-v2
[thirdparty/systemd.git] / src / shared / cgroup-show.c
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
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
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
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <dirent.h>
21 #include <errno.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "alloc-util.h"
28 #include "bus-error.h"
29 #include "bus-util.h"
30 #include "cgroup-show.h"
31 #include "cgroup-util.h"
32 #include "fd-util.h"
33 #include "fileio.h"
34 #include "format-util.h"
35 #include "locale-util.h"
36 #include "macro.h"
37 #include "output-mode.h"
38 #include "path-util.h"
39 #include "process-util.h"
40 #include "string-util.h"
41 #include "terminal-util.h"
42 #include "unit-name.h"
43
44 static void show_pid_array(
45 pid_t pids[],
46 unsigned n_pids,
47 const char *prefix,
48 unsigned n_columns,
49 bool extra,
50 bool more,
51 OutputFlags flags) {
52
53 unsigned i, j, pid_width;
54
55 if (n_pids == 0)
56 return;
57
58 qsort(pids, n_pids, sizeof(pid_t), pid_compare_func);
59
60 /* Filter duplicates */
61 for (j = 0, i = 1; i < n_pids; i++) {
62 if (pids[i] == pids[j])
63 continue;
64 pids[++j] = pids[i];
65 }
66 n_pids = j + 1;
67 pid_width = DECIMAL_STR_WIDTH(pids[j]);
68
69 if (flags & OUTPUT_FULL_WIDTH)
70 n_columns = 0;
71 else {
72 if (n_columns > pid_width+2)
73 n_columns -= pid_width+2;
74 else
75 n_columns = 20;
76 }
77 for (i = 0; i < n_pids; i++) {
78 _cleanup_free_ char *t = NULL;
79
80 (void) get_process_cmdline(pids[i], n_columns, true, &t);
81
82 if (extra)
83 printf("%s%s ", prefix, special_glyph(TRIANGULAR_BULLET));
84 else
85 printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? TREE_BRANCH : TREE_RIGHT)));
86
87 printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
88 }
89 }
90
91 static int show_cgroup_one_by_path(
92 const char *path,
93 const char *prefix,
94 unsigned n_columns,
95 bool more,
96 OutputFlags flags) {
97
98 char *fn;
99 _cleanup_fclose_ FILE *f = NULL;
100 size_t n = 0, n_allocated = 0;
101 _cleanup_free_ pid_t *pids = NULL;
102 _cleanup_free_ char *p = NULL;
103 pid_t pid;
104 int r;
105
106 r = cg_mangle_path(path, &p);
107 if (r < 0)
108 return r;
109
110 fn = strjoina(p, "/cgroup.procs");
111 f = fopen(fn, "re");
112 if (!f)
113 return -errno;
114
115 while ((r = cg_read_pid(f, &pid)) > 0) {
116
117 if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0)
118 continue;
119
120 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
121 return -ENOMEM;
122
123 assert(n < n_allocated);
124 pids[n++] = pid;
125 }
126
127 if (r < 0)
128 return r;
129
130 show_pid_array(pids, n, prefix, n_columns, false, more, flags);
131
132 return 0;
133 }
134
135 int show_cgroup_by_path(
136 const char *path,
137 const char *prefix,
138 unsigned n_columns,
139 OutputFlags flags) {
140
141 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
142 _cleanup_closedir_ DIR *d = NULL;
143 char *gn = NULL;
144 bool shown_pids = false;
145 int r;
146
147 assert(path);
148
149 if (n_columns <= 0)
150 n_columns = columns();
151
152 prefix = strempty(prefix);
153
154 r = cg_mangle_path(path, &fn);
155 if (r < 0)
156 return r;
157
158 d = opendir(fn);
159 if (!d)
160 return -errno;
161
162 while ((r = cg_read_subgroup(d, &gn)) > 0) {
163 _cleanup_free_ char *k = NULL;
164
165 k = strjoin(fn, "/", gn);
166 free(gn);
167 if (!k)
168 return -ENOMEM;
169
170 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
171 continue;
172
173 if (!shown_pids) {
174 show_cgroup_one_by_path(path, prefix, n_columns, true, flags);
175 shown_pids = true;
176 }
177
178 if (last) {
179 printf("%s%s%s\n", prefix, special_glyph(TREE_BRANCH), cg_unescape(basename(last)));
180
181 if (!p1) {
182 p1 = strappend(prefix, special_glyph(TREE_VERTICAL));
183 if (!p1)
184 return -ENOMEM;
185 }
186
187 show_cgroup_by_path(last, p1, n_columns-2, flags);
188 free(last);
189 }
190
191 last = k;
192 k = NULL;
193 }
194
195 if (r < 0)
196 return r;
197
198 if (!shown_pids)
199 show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags);
200
201 if (last) {
202 printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), cg_unescape(basename(last)));
203
204 if (!p2) {
205 p2 = strappend(prefix, " ");
206 if (!p2)
207 return -ENOMEM;
208 }
209
210 show_cgroup_by_path(last, p2, n_columns-2, flags);
211 }
212
213 return 0;
214 }
215
216 int show_cgroup(const char *controller,
217 const char *path,
218 const char *prefix,
219 unsigned n_columns,
220 OutputFlags flags) {
221 _cleanup_free_ char *p = NULL;
222 int r;
223
224 assert(path);
225
226 r = cg_get_path(controller, path, NULL, &p);
227 if (r < 0)
228 return r;
229
230 return show_cgroup_by_path(p, prefix, n_columns, flags);
231 }
232
233 static 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
242 _cleanup_free_ pid_t *copy = NULL;
243 unsigned i, j;
244 int r;
245
246 assert(path);
247
248 if (n_pids <= 0)
249 return 0;
250
251 if (n_columns <= 0)
252 n_columns = columns();
253
254 prefix = strempty(prefix);
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++) {
261 _cleanup_free_ char *k = NULL;
262
263 r = cg_pid_get_path(controller, pids[i], &k);
264 if (r < 0)
265 return r;
266
267 if (path_startswith(k, path))
268 continue;
269
270 copy[j++] = pids[i];
271 }
272
273 show_pid_array(copy, j, prefix, n_columns, true, false, flags);
274
275 return 0;
276 }
277
278 int show_cgroup_and_extra(
279 const char *controller,
280 const char *path,
281 const char *prefix,
282 unsigned n_columns,
283 const pid_t extra_pids[],
284 unsigned n_extra_pids,
285 OutputFlags flags) {
286
287 int r;
288
289 assert(path);
290
291 r = show_cgroup(controller, path, prefix, n_columns, flags);
292 if (r < 0)
293 return r;
294
295 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
296 }
297
298 int show_cgroup_and_extra_by_spec(
299 const char *spec,
300 const char *prefix,
301 unsigned n_columns,
302 const pid_t extra_pids[],
303 unsigned n_extra_pids,
304 OutputFlags flags) {
305
306 _cleanup_free_ char *controller = NULL, *path = NULL;
307 int r;
308
309 assert(spec);
310
311 r = cg_split_spec(spec, &controller, &path);
312 if (r < 0)
313 return r;
314
315 return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
316 }
317
318 int 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
346 int show_cgroup_get_path_and_warn(
347 const char *machine,
348 const char *prefix,
349 char **ret) {
350
351 int r;
352 _cleanup_free_ char *root = NULL;
353
354 if (machine) {
355 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
356 _cleanup_free_ char *unit = NULL;
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");
363
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
368 r = show_cgroup_get_unit_path_and_warn(bus, unit, &root);
369 if (r < 0)
370 return r;
371 } else {
372 r = cg_get_root_path(&root);
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");
378 }
379
380 if (prefix) {
381 char *t;
382
383 t = strjoin(root, prefix);
384 if (!t)
385 return log_oom();
386
387 *ret = t;
388 } else {
389 *ret = root;
390 root = NULL;
391 }
392
393 return 0;
394 }