chiark / gitweb /
journalctl: support --root for message catalogs
[elogind.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         FILE *f;
108         size_t n = 0, n_allocated = 0;
109         pid_t *pids = NULL;
110         char *p;
111         pid_t pid;
112         int r;
113
114         r = cg_fix_path(path, &p);
115         if (r < 0)
116                 return r;
117
118         r = asprintf(&fn, "%s/cgroup.procs", p);
119         free(p);
120         if (r < 0)
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                                 r = -ENOMEM;
141                                 goto finish;
142                         }
143
144                         pids = npids;
145                 }
146
147                 assert(n < n_allocated);
148                 pids[n++] = pid;
149         }
150
151         if (r < 0)
152                 goto finish;
153
154         if (n > 0)
155                 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
156
157         r = 0;
158
159 finish:
160         free(pids);
161
162         if (f)
163                 fclose(f);
164
165         return r;
166 }
167
168 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
169         DIR *d;
170         char *last = NULL;
171         char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
172         bool shown_pids = false;
173         int r;
174
175         assert(path);
176
177         if (n_columns <= 0)
178                 n_columns = columns();
179
180         if (!prefix)
181                 prefix = "";
182
183         r = cg_fix_path(path, &fn);
184         if (r < 0)
185                 return r;
186
187         d = opendir(fn);
188         if (!d) {
189                 free(fn);
190                 return -errno;
191         }
192
193         while ((r = cg_read_subgroup(d, &gn)) > 0) {
194                 char *k;
195
196                 r = asprintf(&k, "%s/%s", fn, gn);
197                 free(gn);
198                 if (r < 0) {
199                         r = -ENOMEM;
200                         goto finish;
201                 }
202
203                 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0) {
204                         free(k);
205                         continue;
206                 }
207
208                 if (!shown_pids) {
209                         show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
210                         shown_pids = true;
211                 }
212
213                 if (last) {
214                         printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
215                                            path_get_file_name(last));
216
217                         if (!p1) {
218                                 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
219                                 if (!p1) {
220                                         free(k);
221                                         r = -ENOMEM;
222                                         goto finish;
223                                 }
224                         }
225
226                         show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
227                         free(last);
228                 }
229
230                 last = k;
231         }
232
233         if (r < 0)
234                 goto finish;
235
236         if (!shown_pids)
237                 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
238
239         if (last) {
240                 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
241                                    path_get_file_name(last));
242
243                 if (!p2) {
244                         p2 = strappend(prefix, "  ");
245                         if (!p2) {
246                                 r = -ENOMEM;
247                                 goto finish;
248                         }
249                 }
250
251                 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
252         }
253
254         r = 0;
255
256 finish:
257         free(p1);
258         free(p2);
259         free(last);
260         free(fn);
261
262         closedir(d);
263
264         return r;
265 }
266
267 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
268         char *p;
269         int r;
270
271         assert(controller);
272         assert(path);
273
274         r = cg_get_path(controller, path, NULL, &p);
275         if (r < 0)
276                 return r;
277
278         r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
279         free(p);
280
281         return r;
282 }
283
284 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) {
285         pid_t *copy;
286         unsigned i, j;
287         int r;
288
289         assert(controller);
290         assert(path);
291
292         if (n_pids <= 0)
293                 return 0;
294
295         if (n_columns <= 0)
296                 n_columns = columns();
297
298         if (!prefix)
299                 prefix = "";
300
301         copy = new(pid_t, n_pids);
302         if (!copy)
303                 return -ENOMEM;
304
305         for (i = 0, j = 0; i < n_pids; i++) {
306                 char *k;
307
308                 r = cg_get_by_pid(controller, pids[i], &k);
309                 if (r < 0) {
310                         free(copy);
311                         return r;
312                 }
313
314                 if (path_startswith(k, path))
315                         continue;
316
317                 copy[j++] = pids[i];
318         }
319
320         show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
321
322         free(copy);
323         return 0;
324 }
325
326 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) {
327         int r;
328
329         assert(controller);
330         assert(path);
331
332         r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
333         if (r < 0)
334                 return r;
335
336         return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
337 }
338
339 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) {
340         int r;
341         _cleanup_free_ char *controller = NULL, *path = NULL;
342
343         assert(spec);
344
345         r = cg_split_spec(spec, &controller, &path);
346         if (r < 0)
347                 return r;
348
349         return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
350 }