1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
15 #include "alloc-util.h"
16 #include "bus-error.h"
18 #include "cgroup-show.h"
19 #include "cgroup-util.h"
22 #include "format-util.h"
23 #include "locale-util.h"
25 #include "output-mode.h"
26 #include "path-util.h"
27 #include "process-util.h"
28 #include "string-util.h"
29 #include "terminal-util.h"
30 #include "unit-name.h"
32 static void show_pid_array(
41 unsigned i
, j
, pid_width
;
46 qsort(pids
, n_pids
, sizeof(pid_t
), pid_compare_func
);
48 /* Filter duplicates */
49 for (j
= 0, i
= 1; i
< n_pids
; i
++) {
50 if (pids
[i
] == pids
[j
])
55 pid_width
= DECIMAL_STR_WIDTH(pids
[j
]);
57 if (flags
& OUTPUT_FULL_WIDTH
)
60 if (n_columns
> pid_width
+2)
61 n_columns
-= pid_width
+2;
65 for (i
= 0; i
< n_pids
; i
++) {
66 _cleanup_free_
char *t
= NULL
;
68 (void) get_process_cmdline(pids
[i
], n_columns
, true, &t
);
71 printf("%s%s ", prefix
, special_glyph(TRIANGULAR_BULLET
));
73 printf("%s%s", prefix
, special_glyph(((more
|| i
< n_pids
-1) ? TREE_BRANCH
: TREE_RIGHT
)));
75 printf("%*"PID_PRI
" %s\n", pid_width
, pids
[i
], strna(t
));
79 static int show_cgroup_one_by_path(
87 _cleanup_fclose_
FILE *f
= NULL
;
88 size_t n
= 0, n_allocated
= 0;
89 _cleanup_free_ pid_t
*pids
= NULL
;
90 _cleanup_free_
char *p
= NULL
;
94 r
= cg_mangle_path(path
, &p
);
98 fn
= strjoina(p
, "/cgroup.procs");
103 while ((r
= cg_read_pid(f
, &pid
)) > 0) {
105 if (!(flags
& OUTPUT_KERNEL_THREADS
) && is_kernel_thread(pid
) > 0)
108 if (!GREEDY_REALLOC(pids
, n_allocated
, n
+ 1))
111 assert(n
< n_allocated
);
118 show_pid_array(pids
, n
, prefix
, n_columns
, false, more
, flags
);
123 int show_cgroup_by_path(
129 _cleanup_free_
char *fn
= NULL
, *p1
= NULL
, *last
= NULL
, *p2
= NULL
;
130 _cleanup_closedir_
DIR *d
= NULL
;
132 bool shown_pids
= false;
138 n_columns
= columns();
140 prefix
= strempty(prefix
);
142 r
= cg_mangle_path(path
, &fn
);
150 while ((r
= cg_read_subgroup(d
, &gn
)) > 0) {
151 _cleanup_free_
char *k
= NULL
;
153 k
= strjoin(fn
, "/", gn
);
158 if (!(flags
& OUTPUT_SHOW_ALL
) && cg_is_empty_recursive(NULL
, k
) > 0)
162 show_cgroup_one_by_path(path
, prefix
, n_columns
, true, flags
);
167 printf("%s%s%s\n", prefix
, special_glyph(TREE_BRANCH
), cg_unescape(basename(last
)));
170 p1
= strappend(prefix
, special_glyph(TREE_VERTICAL
));
175 show_cgroup_by_path(last
, p1
, n_columns
-2, flags
);
186 show_cgroup_one_by_path(path
, prefix
, n_columns
, !!last
, flags
);
189 printf("%s%s%s\n", prefix
, special_glyph(TREE_RIGHT
), cg_unescape(basename(last
)));
192 p2
= strappend(prefix
, " ");
197 show_cgroup_by_path(last
, p2
, n_columns
-2, flags
);
203 int show_cgroup(const char *controller
,
208 _cleanup_free_
char *p
= NULL
;
213 r
= cg_get_path(controller
, path
, NULL
, &p
);
217 return show_cgroup_by_path(p
, prefix
, n_columns
, flags
);
220 static int show_extra_pids(
221 const char *controller
,
229 _cleanup_free_ pid_t
*copy
= NULL
;
239 n_columns
= columns();
241 prefix
= strempty(prefix
);
243 copy
= new(pid_t
, n_pids
);
247 for (i
= 0, j
= 0; i
< n_pids
; i
++) {
248 _cleanup_free_
char *k
= NULL
;
250 r
= cg_pid_get_path(controller
, pids
[i
], &k
);
254 if (path_startswith(k
, path
))
260 show_pid_array(copy
, j
, prefix
, n_columns
, true, false, flags
);
265 int show_cgroup_and_extra(
266 const char *controller
,
270 const pid_t extra_pids
[],
271 unsigned n_extra_pids
,
278 r
= show_cgroup(controller
, path
, prefix
, n_columns
, flags
);
282 return show_extra_pids(controller
, path
, prefix
, n_columns
, extra_pids
, n_extra_pids
, flags
);
285 int show_cgroup_and_extra_by_spec(
289 const pid_t extra_pids
[],
290 unsigned n_extra_pids
,
293 _cleanup_free_
char *controller
= NULL
, *path
= NULL
;
298 r
= cg_split_spec(spec
, &controller
, &path
);
302 return show_cgroup_and_extra(controller
, path
, prefix
, n_columns
, extra_pids
, n_extra_pids
, flags
);
305 int show_cgroup_get_unit_path_and_warn(
310 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
311 _cleanup_free_
char *path
= NULL
;
314 path
= unit_dbus_path_from_name(unit
);
318 r
= sd_bus_get_property_string(
320 "org.freedesktop.systemd1",
322 unit_dbus_interface_from_name(unit
),
327 return log_error_errno(r
, "Failed to query unit control group path: %s",
328 bus_error_message(&error
, r
));
333 int show_cgroup_get_path_and_warn(
339 _cleanup_free_
char *root
= NULL
;
342 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
343 _cleanup_free_
char *unit
= NULL
;
346 m
= strjoina("/run/systemd/machines/", machine
);
347 r
= parse_env_file(m
, NEWLINE
, "SCOPE", &unit
, NULL
);
349 return log_error_errno(r
, "Failed to load machine data: %m");
351 r
= bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL
, NULL
, false, &bus
);
353 return log_error_errno(r
, "Failed to create bus connection: %m");
355 r
= show_cgroup_get_unit_path_and_warn(bus
, unit
, &root
);
359 r
= cg_get_root_path(&root
);
361 return log_error_errno(r
, "Failed to get root control group path.\n"
362 "No cgroup filesystem mounted on /sys/fs/cgroup");
364 return log_error_errno(r
, "Failed to get root control group path: %m");
370 t
= strjoin(root
, prefix
);
376 *ret
= TAKE_PTR(root
);