]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
systemctl: show main and control PID explicitly in cgroup-show
[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 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 }