]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
9ee532ca22271c3dee9f5d0385668975b7f9d4a5
[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 "macro.h"
29 #include "path-util.h"
30 #include "cgroup-util.h"
31 #include "cgroup-show.h"
32
33 static int compare(const void *a, const void *b) {
34 const pid_t *p = a, *q = b;
35
36 if (*p < *q)
37 return -1;
38 if (*p > *q)
39 return 1;
40 return 0;
41 }
42
43 static unsigned ilog10(unsigned long ul) {
44 int n = 0;
45
46 while (ul > 0) {
47 n++;
48 ul /= 10;
49 }
50
51 return n;
52 }
53
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;
56 pid_t biggest = 0;
57
58 /* Filter duplicates */
59 m = 0;
60 for (i = 0; i < n_pids; i++) {
61 unsigned j;
62
63 if (pids[i] > biggest)
64 biggest = pids[i];
65
66 for (j = i+1; j < n_pids; j++)
67 if (pids[i] == pids[j])
68 break;
69
70 if (j >= n_pids)
71 pids[m++] = pids[i];
72 }
73 n_pids = m;
74 pid_width = ilog10(biggest);
75
76 /* And sort */
77 qsort(pids, n_pids, sizeof(pid_t), compare);
78
79 if(flags & OUTPUT_FULL_WIDTH)
80 n_columns = 0;
81 else {
82 if (n_columns > pid_width+2)
83 n_columns -= pid_width+2;
84 else
85 n_columns = 20;
86 }
87 for (i = 0; i < n_pids; i++) {
88 char *t = NULL;
89
90 get_process_cmdline(pids[i], n_columns, true, &t);
91
92 printf("%s%s%*lu %s\n",
93 prefix,
94 draw_special_char(extra ? DRAW_TRIANGULAR_BULLET :
95 ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)),
96 pid_width,
97 (unsigned long) pids[i],
98 strna(t));
99
100 free(t);
101 }
102 }
103
104
105 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
106 char *fn;
107 _cleanup_fclose_ FILE *f = NULL;
108 size_t n = 0, n_allocated = 0;
109 _cleanup_free_ pid_t *pids = NULL;
110 char *p = NULL;
111 pid_t pid;
112 int r;
113
114 r = cg_mangle_path(path, &p);
115 if (r < 0)
116 return r;
117
118 fn = strappend(p, "/cgroup.procs");
119 free(p);
120 if (!fn)
121 return -ENOMEM;
122
123 f = fopen(fn, "re");
124 free(fn);
125 if (!f)
126 return -errno;
127
128 while ((r = cg_read_pid(f, &pid)) > 0) {
129
130 if (!kernel_threads && is_kernel_thread(pid) > 0)
131 continue;
132
133 if (n >= n_allocated) {
134 pid_t *npids;
135
136 n_allocated = MAX(16U, n*2U);
137
138 npids = realloc(pids, sizeof(pid_t) * n_allocated);
139 if (!npids)
140 return -ENOMEM;
141
142 pids = npids;
143 }
144
145 assert(n < n_allocated);
146 pids[n++] = pid;
147 }
148
149 if (r < 0)
150 return r;
151
152 if (n > 0)
153 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
154
155 return 0;
156 }
157
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;
161 char *gn = NULL;
162 bool shown_pids = false;
163 int r;
164
165 assert(path);
166
167 if (n_columns <= 0)
168 n_columns = columns();
169
170 if (!prefix)
171 prefix = "";
172
173 r = cg_mangle_path(path, &fn);
174 if (r < 0)
175 return r;
176
177 d = opendir(fn);
178 if (!d)
179 return -errno;
180
181 while ((r = cg_read_subgroup(d, &gn)) > 0) {
182 _cleanup_free_ char *k = NULL;
183
184 k = strjoin(fn, "/", gn, NULL);
185 free(gn);
186 if (!k)
187 return -ENOMEM;
188
189 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
190 continue;
191
192 if (!shown_pids) {
193 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
194 shown_pids = true;
195 }
196
197 if (last) {
198 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
199 path_get_file_name(last));
200
201 if (!p1) {
202 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
203 if (!p1)
204 return -ENOMEM;
205 }
206
207 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
208 free(last);
209 }
210
211 last = k;
212 k = NULL;
213 }
214
215 if (r < 0)
216 return r;
217
218 if (!shown_pids)
219 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
220
221 if (last) {
222 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
223 path_get_file_name(last));
224
225 if (!p2) {
226 p2 = strappend(prefix, " ");
227 if (!p2)
228 return -ENOMEM;
229 }
230
231 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
232 }
233
234 return 0;
235 }
236
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;
239 int r;
240
241 assert(path);
242
243 r = cg_get_path(controller, path, NULL, &p);
244 if (r < 0)
245 return r;
246
247 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
248 }
249
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;
252 unsigned i, j;
253 int r;
254
255 assert(controller);
256 assert(path);
257
258 if (n_pids <= 0)
259 return 0;
260
261 if (n_columns <= 0)
262 n_columns = columns();
263
264 prefix = strempty(prefix);
265
266 copy = new(pid_t, n_pids);
267 if (!copy)
268 return -ENOMEM;
269
270 for (i = 0, j = 0; i < n_pids; i++) {
271 char _cleanup_free_ *k = NULL;
272
273 r = cg_pid_get_path(controller, pids[i], &k);
274 if (r < 0)
275 return r;
276
277 if (path_startswith(k, path))
278 continue;
279
280 copy[j++] = pids[i];
281 }
282
283 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
284
285 return 0;
286 }
287
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) {
289 int r;
290
291 assert(path);
292
293 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
294 if (r < 0)
295 return r;
296
297 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
298 }
299
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;
302 int r;
303
304 assert(spec);
305
306 r = cg_split_spec(spec, &controller, &path);
307 if (r < 0)
308 return r;
309
310 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
311 }