]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
cgls: don't show empty cgroups by default
[thirdparty/systemd.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 }