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