1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
10 #include "bus-error.h"
12 #include "cgroup-show.h"
13 #include "cgroup-util.h"
16 #include "format-util.h"
17 #include "locale-util.h"
19 #include "output-mode.h"
20 #include "parse-util.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 #include "xattr-util.h"
29 static void show_pid_array(
38 unsigned i
, j
, pid_width
;
43 typesafe_qsort(pids
, n_pids
, pid_compare_func
);
45 /* Filter duplicates */
46 for (j
= 0, i
= 1; i
< n_pids
; i
++) {
47 if (pids
[i
] == pids
[j
])
52 pid_width
= DECIMAL_STR_WIDTH(pids
[j
]);
54 if (flags
& OUTPUT_FULL_WIDTH
)
57 if (n_columns
> pid_width
+ 3) /* something like "├─1114784 " */
58 n_columns
-= pid_width
+ 3;
62 for (i
= 0; i
< n_pids
; i
++) {
63 _cleanup_free_
char *t
= NULL
;
65 (void) get_process_cmdline(pids
[i
], n_columns
,
66 PROCESS_CMDLINE_COMM_FALLBACK
| PROCESS_CMDLINE_USE_LOCALE
,
70 printf("%s%s ", prefix
, special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET
));
72 printf("%s%s", prefix
, special_glyph(((more
|| i
< n_pids
-1) ? SPECIAL_GLYPH_TREE_BRANCH
: SPECIAL_GLYPH_TREE_RIGHT
)));
74 printf("%s%*"PID_PRI
" %s%s\n", ansi_grey(), pid_width
, pids
[i
], strna(t
), ansi_normal());
78 static int show_cgroup_one_by_path(
85 _cleanup_free_ pid_t
*pids
= NULL
;
86 _cleanup_fclose_
FILE *f
= NULL
;
87 _cleanup_free_
char *p
= NULL
;
93 r
= cg_mangle_path(path
, &p
);
97 fn
= strjoina(p
, "/cgroup.procs");
102 while ((r
= cg_read_pid(f
, &pid
)) > 0) {
104 if (!(flags
& OUTPUT_KERNEL_THREADS
) && is_kernel_thread(pid
) > 0)
107 if (!GREEDY_REALLOC(pids
, n
+ 1))
116 show_pid_array(pids
, n
, prefix
, n_columns
, false, more
, flags
);
121 static int show_cgroup_name(
126 _cleanup_free_
char *b
= NULL
;
127 bool delegate
= false;
130 r
= getxattr_malloc(path
, "trusted.delegate", &b
, false);
133 log_debug_errno(r
, "Failed to read trusted.delegate extended attribute: %m");
135 r
= parse_boolean(b
);
137 log_debug_errno(r
, "Failed to parse trusted.delegate extended attribute boolean value: %m");
144 b
= strdup(basename(path
));
148 printf("%s%s%s%s%s %s%s%s\n",
150 delegate
? ansi_underline() : "",
152 delegate
? ansi_normal() : "",
153 delegate
? ansi_highlight() : "",
154 delegate
? special_glyph(SPECIAL_GLYPH_ELLIPSIS
) : "",
155 delegate
? ansi_normal() : "");
159 int show_cgroup_by_path(
165 _cleanup_free_
char *fn
= NULL
, *p1
= NULL
, *last
= NULL
, *p2
= NULL
;
166 _cleanup_closedir_
DIR *d
= NULL
;
167 bool shown_pids
= false;
174 n_columns
= columns();
176 prefix
= strempty(prefix
);
178 r
= cg_mangle_path(path
, &fn
);
186 while ((r
= cg_read_subgroup(d
, &gn
)) > 0) {
187 _cleanup_free_
char *k
= NULL
;
189 k
= path_join(fn
, gn
);
194 if (!(flags
& OUTPUT_SHOW_ALL
) && cg_is_empty_recursive(NULL
, k
) > 0)
198 show_cgroup_one_by_path(path
, prefix
, n_columns
, true, flags
);
203 r
= show_cgroup_name(last
, prefix
, special_glyph(SPECIAL_GLYPH_TREE_BRANCH
));
208 p1
= strjoin(prefix
, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL
));
213 show_cgroup_by_path(last
, p1
, n_columns
-2, flags
);
224 show_cgroup_one_by_path(path
, prefix
, n_columns
, !!last
, flags
);
227 r
= show_cgroup_name(last
, prefix
, special_glyph(SPECIAL_GLYPH_TREE_RIGHT
));
232 p2
= strjoin(prefix
, " ");
237 show_cgroup_by_path(last
, p2
, n_columns
-2, flags
);
243 int show_cgroup(const char *controller
,
248 _cleanup_free_
char *p
= NULL
;
253 r
= cg_get_path(controller
, path
, NULL
, &p
);
257 return show_cgroup_by_path(p
, prefix
, n_columns
, flags
);
260 static int show_extra_pids(
261 const char *controller
,
269 _cleanup_free_ pid_t
*copy
= NULL
;
279 n_columns
= columns();
281 prefix
= strempty(prefix
);
283 copy
= new(pid_t
, n_pids
);
287 for (i
= 0, j
= 0; i
< n_pids
; i
++) {
288 _cleanup_free_
char *k
= NULL
;
290 r
= cg_pid_get_path(controller
, pids
[i
], &k
);
294 if (path_startswith(k
, path
))
300 show_pid_array(copy
, j
, prefix
, n_columns
, true, false, flags
);
305 int show_cgroup_and_extra(
306 const char *controller
,
310 const pid_t extra_pids
[],
311 unsigned n_extra_pids
,
318 r
= show_cgroup(controller
, path
, prefix
, n_columns
, flags
);
322 return show_extra_pids(controller
, path
, prefix
, n_columns
, extra_pids
, n_extra_pids
, flags
);
325 int show_cgroup_get_unit_path_and_warn(
330 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
331 _cleanup_free_
char *path
= NULL
;
334 path
= unit_dbus_path_from_name(unit
);
338 r
= sd_bus_get_property_string(
340 "org.freedesktop.systemd1",
342 unit_dbus_interface_from_name(unit
),
347 return log_error_errno(r
, "Failed to query unit control group path: %s",
348 bus_error_message(&error
, r
));
353 int show_cgroup_get_path_and_warn(
359 _cleanup_free_
char *root
= NULL
;
362 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
363 _cleanup_free_
char *unit
= NULL
;
366 m
= strjoina("/run/systemd/machines/", machine
);
367 r
= parse_env_file(NULL
, m
, "SCOPE", &unit
);
369 return log_error_errno(r
, "Failed to load machine data: %m");
371 r
= bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL
, NULL
, false, &bus
);
373 return bus_log_connect_error(r
);
375 r
= show_cgroup_get_unit_path_and_warn(bus
, unit
, &root
);
379 r
= cg_get_root_path(&root
);
381 return log_error_errno(r
, "Failed to get root control group path.\n"
382 "No cgroup filesystem mounted on /sys/fs/cgroup");
384 return log_error_errno(r
, "Failed to get root control group path: %m");
390 t
= strjoin(root
, prefix
);
396 *ret
= TAKE_PTR(root
);