]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
Merge pull request #1062 from poettering/cgroups-show
[thirdparty/systemd.git] / src / shared / cgroup-show.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <dirent.h>
25 #include <errno.h>
26
27 #include "util.h"
28 #include "formats-util.h"
29 #include "process-util.h"
30 #include "macro.h"
31 #include "path-util.h"
32 #include "cgroup-util.h"
33 #include "cgroup-show.h"
34 #include "terminal-util.h"
35
36 static int compare(const void *a, const void *b) {
37 const pid_t *p = a, *q = b;
38
39 if (*p < *q)
40 return -1;
41 if (*p > *q)
42 return 1;
43 return 0;
44 }
45
46 static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
47 unsigned i, j, pid_width;
48
49 if (n_pids == 0)
50 return;
51
52 qsort(pids, n_pids, sizeof(pid_t), compare);
53
54 /* Filter duplicates */
55 for (j = 0, i = 1; i < n_pids; i++) {
56 if (pids[i] == pids[j])
57 continue;
58 pids[++j] = pids[i];
59 }
60 n_pids = j + 1;
61 pid_width = DECIMAL_STR_WIDTH(pids[j]);
62
63 if (flags & OUTPUT_FULL_WIDTH)
64 n_columns = 0;
65 else {
66 if (n_columns > pid_width+2)
67 n_columns -= pid_width+2;
68 else
69 n_columns = 20;
70 }
71 for (i = 0; i < n_pids; i++) {
72 _cleanup_free_ char *t = NULL;
73
74 get_process_cmdline(pids[i], n_columns, true, &t);
75
76 if (extra)
77 printf("%s%s ", prefix, draw_special_char(DRAW_TRIANGULAR_BULLET));
78 else
79 printf("%s%s", prefix, draw_special_char(((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)));
80
81 printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
82 }
83 }
84
85
86 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
87 char *fn;
88 _cleanup_fclose_ FILE *f = NULL;
89 size_t n = 0, n_allocated = 0;
90 _cleanup_free_ pid_t *pids = NULL;
91 _cleanup_free_ char *p = NULL;
92 pid_t pid;
93 int r;
94
95 r = cg_mangle_path(path, &p);
96 if (r < 0)
97 return r;
98
99 fn = strjoina(p, "/cgroup.procs");
100 f = fopen(fn, "re");
101 if (!f)
102 return -errno;
103
104 while ((r = cg_read_pid(f, &pid)) > 0) {
105
106 if (!kernel_threads && is_kernel_thread(pid) > 0)
107 continue;
108
109 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
110 return -ENOMEM;
111
112 assert(n < n_allocated);
113 pids[n++] = pid;
114 }
115
116 if (r < 0)
117 return r;
118
119 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
120
121 return 0;
122 }
123
124 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
125 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
126 _cleanup_closedir_ DIR *d = NULL;
127 char *gn = NULL;
128 bool shown_pids = false;
129 int r;
130
131 assert(path);
132
133 if (n_columns <= 0)
134 n_columns = columns();
135
136 if (!prefix)
137 prefix = "";
138
139 r = cg_mangle_path(path, &fn);
140 if (r < 0)
141 return r;
142
143 d = opendir(fn);
144 if (!d)
145 return -errno;
146
147 while ((r = cg_read_subgroup(d, &gn)) > 0) {
148 _cleanup_free_ char *k = NULL;
149
150 k = strjoin(fn, "/", gn, NULL);
151 free(gn);
152 if (!k)
153 return -ENOMEM;
154
155 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
156 continue;
157
158 if (!shown_pids) {
159 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
160 shown_pids = true;
161 }
162
163 if (last) {
164 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last)));
165
166 if (!p1) {
167 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
168 if (!p1)
169 return -ENOMEM;
170 }
171
172 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
173 free(last);
174 }
175
176 last = k;
177 k = NULL;
178 }
179
180 if (r < 0)
181 return r;
182
183 if (!shown_pids)
184 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
185
186 if (last) {
187 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
188
189 if (!p2) {
190 p2 = strappend(prefix, " ");
191 if (!p2)
192 return -ENOMEM;
193 }
194
195 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
196 }
197
198 return 0;
199 }
200
201 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
202 _cleanup_free_ char *p = NULL;
203 int r;
204
205 assert(path);
206
207 r = cg_get_path(controller, path, NULL, &p);
208 if (r < 0)
209 return r;
210
211 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
212 }
213
214 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) {
215 _cleanup_free_ pid_t *copy = NULL;
216 unsigned i, j;
217 int r;
218
219 assert(path);
220
221 if (n_pids <= 0)
222 return 0;
223
224 if (n_columns <= 0)
225 n_columns = columns();
226
227 prefix = strempty(prefix);
228
229 copy = new(pid_t, n_pids);
230 if (!copy)
231 return -ENOMEM;
232
233 for (i = 0, j = 0; i < n_pids; i++) {
234 _cleanup_free_ char *k = NULL;
235
236 r = cg_pid_get_path(controller, pids[i], &k);
237 if (r < 0)
238 return r;
239
240 if (path_startswith(k, path))
241 continue;
242
243 copy[j++] = pids[i];
244 }
245
246 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
247
248 return 0;
249 }
250
251 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) {
252 int r;
253
254 assert(path);
255
256 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
257 if (r < 0)
258 return r;
259
260 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
261 }
262
263 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) {
264 _cleanup_free_ char *controller = NULL, *path = NULL;
265 int r;
266
267 assert(spec);
268
269 r = cg_split_spec(spec, &controller, &path);
270 if (r < 0)
271 return r;
272
273 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
274 }