chiark / gitweb /
nspawn: introduce the new /machine/ tree in the cgroup tree and move containers there
[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         _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 }