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 unsigned ilog10(unsigned long ul) {
54 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) {
55 unsigned i, m, pid_width;
58 /* Filter duplicates */
60 for (i = 0; i < n_pids; i++) {
63 if (pids[i] > biggest)
66 for (j = i+1; j < n_pids; j++)
67 if (pids[i] == pids[j])
74 pid_width = ilog10(biggest);
77 qsort(pids, n_pids, sizeof(pid_t), compare);
79 if(flags & OUTPUT_FULL_WIDTH)
82 if (n_columns > pid_width+2)
83 n_columns -= pid_width+2;
87 for (i = 0; i < n_pids; i++) {
90 get_process_cmdline(pids[i], n_columns, true, &t);
92 printf("%s%s%*lu %s\n",
94 draw_special_char(extra ? DRAW_TRIANGULAR_BULLET :
95 ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)),
97 (unsigned long) pids[i],
105 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
107 _cleanup_fclose_ FILE *f = NULL;
108 size_t n = 0, n_allocated = 0;
109 _cleanup_free_ pid_t *pids = NULL;
114 r = cg_mangle_path(path, &p);
118 fn = strappend(p, "/cgroup.procs");
128 while ((r = cg_read_pid(f, &pid)) > 0) {
130 if (!kernel_threads && is_kernel_thread(pid) > 0)
133 if (n >= n_allocated) {
136 n_allocated = MAX(16U, n*2U);
138 npids = realloc(pids, sizeof(pid_t) * n_allocated);
145 assert(n < n_allocated);
153 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
158 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
159 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
160 _cleanup_closedir_ DIR *d = NULL;
162 bool shown_pids = false;
168 n_columns = columns();
173 r = cg_mangle_path(path, &fn);
181 while ((r = cg_read_subgroup(d, &gn)) > 0) {
182 _cleanup_free_ char *k = NULL;
184 k = strjoin(fn, "/", gn, NULL);
189 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
193 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
198 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
199 path_get_file_name(last));
202 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
207 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
219 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
222 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
223 path_get_file_name(last));
226 p2 = strappend(prefix, " ");
231 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
237 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
238 _cleanup_free_ char *p = NULL;
243 r = cg_get_path(controller, path, NULL, &p);
247 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
250 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) {
251 pid_t _cleanup_free_ *copy = NULL;
262 n_columns = columns();
264 prefix = strempty(prefix);
266 copy = new(pid_t, n_pids);
270 for (i = 0, j = 0; i < n_pids; i++) {
271 char _cleanup_free_ *k = NULL;
273 r = cg_pid_get_path(controller, pids[i], &k);
277 if (path_startswith(k, path))
283 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
288 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) {
293 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
297 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
300 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) {
301 _cleanup_free_ char *controller = NULL, *path = NULL;
306 r = cg_split_spec(spec, &controller, &path);
310 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);