chiark / gitweb /
cgls: don't show empty cgroups by default
[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 int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) {
54         char *fn;
55         FILE *f;
56         size_t n = 0, n_allocated = 0;
57         pid_t *pids = NULL;
58         char *p;
59         pid_t pid, biggest = 0;
60         int r;
61
62         if (n_columns <= 0)
63                 n_columns = columns();
64
65         if (!prefix)
66                 prefix = "";
67
68         if ((r = cg_fix_path(path, &p)) < 0)
69                 return r;
70
71         r = asprintf(&fn, "%s/cgroup.procs", p);
72         free(p);
73
74         if (r < 0)
75                 return -ENOMEM;
76
77         f = fopen(fn, "re");
78         free(fn);
79
80         if (!f)
81                 return -errno;
82
83         while ((r = cg_read_pid(f, &pid)) > 0) {
84
85                 if (!kernel_threads && is_kernel_thread(pid) > 0)
86                         continue;
87
88                 if (n >= n_allocated) {
89                         pid_t *npids;
90
91                         n_allocated = MAX(16U, n*2U);
92
93                         if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
94                                 r = -ENOMEM;
95                                 goto finish;
96                         }
97
98                         pids = npids;
99                 }
100
101                 assert(n < n_allocated);
102                 pids[n++] = pid;
103
104                 if (pid > biggest)
105                         biggest = pid;
106         }
107
108         if (r < 0)
109                 goto finish;
110
111         if (n > 0) {
112                 unsigned i, m;
113
114                 /* Filter duplicates */
115                 m = 0;
116                 for (i = 0; i < n; i++) {
117                         unsigned j;
118
119                         for (j = i+1; j < n; j++)
120                                 if (pids[i] == pids[j])
121                                         break;
122
123                         if (j >= n)
124                                 pids[m++] = pids[i];
125                 }
126                 n = m;
127
128                 /* And sort */
129                 qsort(pids, n, sizeof(pid_t), compare);
130
131                 if (n_columns > 8)
132                         n_columns -= 8;
133                 else
134                         n_columns = 20;
135
136                 for (i = 0; i < n; i++) {
137                         char *t = NULL;
138
139                         get_process_cmdline(pids[i], n_columns, true, &t);
140
141                         printf("%s%s %*lu %s\n",
142                                prefix,
143                                (more || i < n-1) ? "\342\224\234" : "\342\224\224",
144                                (int) ilog10(biggest),
145                                (unsigned long) pids[i],
146                                strna(t));
147
148                         free(t);
149                 }
150         }
151
152         r = 0;
153
154 finish:
155         free(pids);
156
157         if (f)
158                 fclose(f);
159
160         return r;
161 }
162
163 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) {
164         DIR *d;
165         char *last = NULL;
166         char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
167         bool shown_pids = false;
168         int r;
169
170         if (n_columns <= 0)
171                 n_columns = columns();
172
173         if (!prefix)
174                 prefix = "";
175
176         r = cg_fix_path(path, &fn);
177         if (r < 0)
178                 return r;
179
180         d = opendir(fn);
181         if (!d) {
182                 free(fn);
183                 return -errno;
184         }
185
186         while ((r = cg_read_subgroup(d, &gn)) > 0) {
187                 char *k;
188
189                 r = asprintf(&k, "%s/%s", fn, gn);
190                 free(gn);
191
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 }