1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "path-util.h"
30 #include "cgroup-util.h"
31 #include "cgroup-show.h"
33 static int compare(const void *a, const void *b) {
34 const pid_t *p = a, *q = b;
43 static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
44 unsigned i, m, pid_width;
49 /* Filter duplicates */
51 for (i = 0; i < n_pids; i++) {
54 if (pids[i] > biggest)
57 for (j = i+1; j < n_pids; j++)
58 if (pids[i] == pids[j])
65 pid_width = DECIMAL_STR_WIDTH(biggest);
68 qsort(pids, n_pids, sizeof(pid_t), compare);
70 if(flags & OUTPUT_FULL_WIDTH)
73 if (n_columns > pid_width+2)
74 n_columns -= pid_width+2;
78 for (i = 0; i < n_pids; i++) {
81 get_process_cmdline(pids[i], n_columns, true, &t);
83 printf("%s%s%*lu %s\n",
85 draw_special_char(extra ? DRAW_TRIANGULAR_BULLET :
86 ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)),
88 (unsigned long) pids[i],
96 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
98 _cleanup_fclose_ FILE *f = NULL;
99 size_t n = 0, n_allocated = 0;
100 _cleanup_free_ pid_t *pids = NULL;
105 r = cg_mangle_path(path, &p);
109 fn = strappend(p, "/cgroup.procs");
119 while ((r = cg_read_pid(f, &pid)) > 0) {
121 if (!kernel_threads && is_kernel_thread(pid) > 0)
124 if (n >= n_allocated) {
127 n_allocated = MAX(16U, n*2U);
129 npids = realloc(pids, sizeof(pid_t) * n_allocated);
136 assert(n < n_allocated);
144 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
149 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
150 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
151 _cleanup_closedir_ DIR *d = NULL;
153 bool shown_pids = false;
159 n_columns = columns();
164 r = cg_mangle_path(path, &fn);
172 while ((r = cg_read_subgroup(d, &gn)) > 0) {
173 _cleanup_free_ char *k = NULL;
175 k = strjoin(fn, "/", gn, NULL);
180 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
184 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
189 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
190 path_get_file_name(last));
193 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
198 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
210 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
213 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
214 path_get_file_name(last));
217 p2 = strappend(prefix, " ");
222 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
228 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
229 _cleanup_free_ char *p = NULL;
234 r = cg_get_path(controller, path, NULL, &p);
238 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
241 static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids, OutputFlags flags) {
242 _cleanup_free_ pid_t *copy = NULL;
252 n_columns = columns();
254 prefix = strempty(prefix);
256 copy = new(pid_t, n_pids);
260 for (i = 0, j = 0; i < n_pids; i++) {
261 _cleanup_free_ char *k = NULL;
263 r = cg_pid_get_path(controller, pids[i], &k);
267 if (path_startswith(k, path))
273 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
278 int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
283 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
287 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
290 int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
291 _cleanup_free_ char *controller = NULL, *path = NULL;
296 r = cg_split_spec(spec, &controller, &path);
300 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);