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