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