]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
util : fallback to plain ASCII drawing if locale is not UTF-8
[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) {
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 (n_columns > pid_width+2)
80 n_columns -= pid_width+2;
81 else
82 n_columns = 20;
83
84 for (i = 0; i < n_pids; i++) {
85 char *t = NULL;
86
87 get_process_cmdline(pids[i], n_columns, true, &t);
88
89 printf("%s%s %*lu %s\n",
90 prefix,
91 draw_special_char(extra ? DRAW_TRIANGULAR_BULLET :
92 ((more || i < n_pids-1) ? DRAW_BOX_VERT_AND_RIGHT : DRAW_BOX_UP_AND_RIGHT)),
93 pid_width,
94 (unsigned long) pids[i],
95 strna(t));
96
97 free(t);
98 }
99 }
100
101
102 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) {
103 char *fn;
104 FILE *f;
105 size_t n = 0, n_allocated = 0;
106 pid_t *pids = NULL;
107 char *p;
108 pid_t pid;
109 int r;
110
111 r = cg_fix_path(path, &p);
112 if (r < 0)
113 return r;
114
115 r = asprintf(&fn, "%s/cgroup.procs", p);
116 free(p);
117 if (r < 0)
118 return -ENOMEM;
119
120 f = fopen(fn, "re");
121 free(fn);
122 if (!f)
123 return -errno;
124
125 while ((r = cg_read_pid(f, &pid)) > 0) {
126
127 if (!kernel_threads && is_kernel_thread(pid) > 0)
128 continue;
129
130 if (n >= n_allocated) {
131 pid_t *npids;
132
133 n_allocated = MAX(16U, n*2U);
134
135 npids = realloc(pids, sizeof(pid_t) * n_allocated);
136 if (!npids) {
137 r = -ENOMEM;
138 goto finish;
139 }
140
141 pids = npids;
142 }
143
144 assert(n < n_allocated);
145 pids[n++] = pid;
146 }
147
148 if (r < 0)
149 goto finish;
150
151 if (n > 0)
152 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads);
153
154 r = 0;
155
156 finish:
157 free(pids);
158
159 if (f)
160 fclose(f);
161
162 return r;
163 }
164
165 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) {
166 DIR *d;
167 char *last = NULL;
168 char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
169 bool shown_pids = false;
170 int r;
171
172 assert(path);
173
174 if (n_columns <= 0)
175 n_columns = columns();
176
177 if (!prefix)
178 prefix = "";
179
180 r = cg_fix_path(path, &fn);
181 if (r < 0)
182 return r;
183
184 d = opendir(fn);
185 if (!d) {
186 free(fn);
187 return -errno;
188 }
189
190 while ((r = cg_read_subgroup(d, &gn)) > 0) {
191 char *k;
192
193 r = asprintf(&k, "%s/%s", fn, gn);
194 free(gn);
195 if (r < 0) {
196 r = -ENOMEM;
197 goto finish;
198 }
199
200 if (!all && cg_is_empty_recursive(NULL, k, false) > 0) {
201 free(k);
202 continue;
203 }
204
205 if (!shown_pids) {
206 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads);
207 shown_pids = true;
208 }
209
210 if (last) {
211 printf("%s%s %s\n", prefix, draw_special_char(DRAW_BOX_VERT_AND_RIGHT),
212 path_get_file_name(last));
213
214 if (!p1) {
215 p1 = strjoin(prefix, draw_special_char(DRAW_BOX_VERT), " ", NULL);
216 if (!p1) {
217 free(k);
218 r = -ENOMEM;
219 goto finish;
220 }
221 }
222
223 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, all);
224 free(last);
225 }
226
227 last = k;
228 }
229
230 if (r < 0)
231 goto finish;
232
233 if (!shown_pids)
234 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads);
235
236 if (last) {
237 printf("%s%s %s\n", prefix, draw_special_char(DRAW_BOX_UP_AND_RIGHT),
238 path_get_file_name(last));
239
240 if (!p2) {
241 p2 = strappend(prefix, " ");
242 if (!p2) {
243 r = -ENOMEM;
244 goto finish;
245 }
246 }
247
248 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, all);
249 }
250
251 r = 0;
252
253 finish:
254 free(p1);
255 free(p2);
256 free(last);
257 free(fn);
258
259 closedir(d);
260
261 return r;
262 }
263
264 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) {
265 char *p;
266 int r;
267
268 assert(controller);
269 assert(path);
270
271 r = cg_get_path(controller, path, NULL, &p);
272 if (r < 0)
273 return r;
274
275 r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads, all);
276 free(p);
277
278 return r;
279 }
280
281 static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids) {
282 pid_t *copy;
283 unsigned i, j;
284 int r;
285
286 assert(controller);
287 assert(path);
288
289 if (n_pids <= 0)
290 return 0;
291
292 if (n_columns <= 0)
293 n_columns = columns();
294
295 if (!prefix)
296 prefix = "";
297
298 copy = new(pid_t, n_pids);
299 if (!copy)
300 return -ENOMEM;
301
302 for (i = 0, j = 0; i < n_pids; i++) {
303 char *k;
304
305 r = cg_get_by_pid(controller, pids[i], &k);
306 if (r < 0) {
307 free(copy);
308 return r;
309 }
310
311 if (path_startswith(k, path))
312 continue;
313
314 copy[j++] = pids[i];
315 }
316
317 show_pid_array(copy, j, prefix, n_columns, true, false, false);
318
319 free(copy);
320 return 0;
321 }
322
323 int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids) {
324 int r;
325
326 assert(controller);
327 assert(path);
328
329 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, all);
330 if (r < 0)
331 return r;
332
333 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids);
334 }
335
336 int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids) {
337 int r;
338 char *controller, *path;
339
340 assert(spec);
341
342 r = cg_split_spec(spec, &controller, &path);
343 if (r < 0)
344 return r;
345
346 r = show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, all, extra_pids, n_extra_pids);
347 free(controller);
348 free(path);
349
350 return r;
351 }