]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cgroup-show.c
systemctl: align all status fields to common column
[thirdparty/systemd.git] / src / shared / cgroup-show.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ab35fb1b
LP
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
5430f7f2
LP
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
ab35fb1b
LP
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
5430f7f2 16 Lesser General Public License for more details.
ab35fb1b 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
ab35fb1b
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
23#include <string.h>
fa776d8e
LP
24#include <dirent.h>
25#include <errno.h>
ab35fb1b
LP
26
27#include "util.h"
28#include "macro.h"
9eb977db 29#include "path-util.h"
c6c18be3 30#include "cgroup-util.h"
ab35fb1b
LP
31#include "cgroup-show.h"
32
33static 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
fa776d8e
LP
43static 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
9bdbc2e2 54static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
4278aa27 55 unsigned i, m, pid_width;
b69d29ce
LP
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;
4278aa27 74 pid_width = ilog10(biggest);
b69d29ce
LP
75
76 /* And sort */
77 qsort(pids, n_pids, sizeof(pid_t), compare);
78
9bdbc2e2
LN
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 }
b69d29ce
LP
87 for (i = 0; i < n_pids; i++) {
88 char *t = NULL;
89
90 get_process_cmdline(pids[i], n_columns, true, &t);
91
45a5ff0d 92 printf("%s%s%*lu %s\n",
b69d29ce 93 prefix,
c339d977 94 draw_special_char(extra ? DRAW_TRIANGULAR_BULLET :
45a5ff0d 95 ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)),
4278aa27 96 pid_width,
b69d29ce
LP
97 (unsigned long) pids[i],
98 strna(t));
99
100 free(t);
101 }
102}
103
104
9bdbc2e2 105static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
ab35fb1b
LP
106 char *fn;
107 FILE *f;
108 size_t n = 0, n_allocated = 0;
109 pid_t *pids = NULL;
fa776d8e 110 char *p;
b69d29ce 111 pid_t pid;
fa776d8e 112 int r;
ab35fb1b 113
b69d29ce
LP
114 r = cg_fix_path(path, &p);
115 if (r < 0)
35d2e7ec 116 return r;
ab35fb1b 117
fa776d8e
LP
118 r = asprintf(&fn, "%s/cgroup.procs", p);
119 free(p);
fa776d8e
LP
120 if (r < 0)
121 return -ENOMEM;
122
123 f = fopen(fn, "re");
ab35fb1b 124 free(fn);
ab35fb1b 125 if (!f)
fa776d8e 126 return -errno;
ab35fb1b 127
c6c18be3 128 while ((r = cg_read_pid(f, &pid)) > 0) {
ab35fb1b 129
1e5678d0
LP
130 if (!kernel_threads && is_kernel_thread(pid) > 0)
131 continue;
132
ab35fb1b
LP
133 if (n >= n_allocated) {
134 pid_t *npids;
135
136 n_allocated = MAX(16U, n*2U);
137
b69d29ce
LP
138 npids = realloc(pids, sizeof(pid_t) * n_allocated);
139 if (!npids) {
fa776d8e 140 r = -ENOMEM;
ab35fb1b
LP
141 goto finish;
142 }
143
144 pids = npids;
145 }
146
147 assert(n < n_allocated);
c6c18be3 148 pids[n++] = pid;
ab35fb1b
LP
149 }
150
c6c18be3
LP
151 if (r < 0)
152 goto finish;
153
b69d29ce 154 if (n > 0)
9bdbc2e2 155 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
ab35fb1b 156
fa776d8e
LP
157 r = 0;
158
ab35fb1b
LP
159finish:
160 free(pids);
161
162 if (f)
163 fclose(f);
fa776d8e
LP
164
165 return r;
166}
167
9bdbc2e2 168int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
fa776d8e
LP
169 DIR *d;
170 char *last = NULL;
35d2e7ec 171 char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
fa776d8e
LP
172 bool shown_pids = false;
173 int r;
174
b69d29ce
LP
175 assert(path);
176
fa776d8e
LP
177 if (n_columns <= 0)
178 n_columns = columns();
179
180 if (!prefix)
181 prefix = "";
182
c3175a7f
LP
183 r = cg_fix_path(path, &fn);
184 if (r < 0)
35d2e7ec 185 return r;
fa776d8e 186
c3175a7f
LP
187 d = opendir(fn);
188 if (!d) {
fa776d8e
LP
189 free(fn);
190 return -errno;
191 }
192
35d2e7ec 193 while ((r = cg_read_subgroup(d, &gn)) > 0) {
c3175a7f
LP
194 char *k;
195
196 r = asprintf(&k, "%s/%s", fn, gn);
197 free(gn);
c3175a7f
LP
198 if (r < 0) {
199 r = -ENOMEM;
200 goto finish;
201 }
202
9bdbc2e2 203 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0) {
c3175a7f
LP
204 free(k);
205 continue;
206 }
fa776d8e
LP
207
208 if (!shown_pids) {
9bdbc2e2 209 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
fa776d8e
LP
210 shown_pids = true;
211 }
212
213 if (last) {
45a5ff0d
MS
214 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
215 path_get_file_name(last));
fa776d8e 216
c3175a7f 217 if (!p1) {
45a5ff0d 218 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
c3175a7f
LP
219 if (!p1) {
220 free(k);
fa776d8e
LP
221 r = -ENOMEM;
222 goto finish;
223 }
c3175a7f 224 }
fa776d8e 225
9bdbc2e2 226 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
fa776d8e 227 free(last);
fa776d8e
LP
228 }
229
c3175a7f 230 last = k;
fa776d8e
LP
231 }
232
35d2e7ec
LP
233 if (r < 0)
234 goto finish;
235
fa776d8e 236 if (!shown_pids)
9bdbc2e2 237 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
fa776d8e
LP
238
239 if (last) {
45a5ff0d
MS
240 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
241 path_get_file_name(last));
fa776d8e 242
c3175a7f
LP
243 if (!p2) {
244 p2 = strappend(prefix, " ");
245 if (!p2) {
fa776d8e
LP
246 r = -ENOMEM;
247 goto finish;
248 }
c3175a7f 249 }
fa776d8e 250
9bdbc2e2 251 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
fa776d8e
LP
252 }
253
254 r = 0;
255
256finish:
257 free(p1);
258 free(p2);
259 free(last);
260 free(fn);
261
262 closedir(d);
263
264 return r;
ab35fb1b 265}
35d2e7ec 266
9bdbc2e2 267int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
35d2e7ec
LP
268 char *p;
269 int r;
270
271 assert(controller);
272 assert(path);
273
1e5678d0
LP
274 r = cg_get_path(controller, path, NULL, &p);
275 if (r < 0)
35d2e7ec
LP
276 return r;
277
9bdbc2e2 278 r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
35d2e7ec
LP
279 free(p);
280
281 return r;
282}
b69d29ce 283
9bdbc2e2 284static 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) {
b69d29ce
LP
285 pid_t *copy;
286 unsigned i, j;
287 int r;
288
289 assert(controller);
290 assert(path);
291
292 if (n_pids <= 0)
293 return 0;
294
295 if (n_columns <= 0)
296 n_columns = columns();
297
298 if (!prefix)
299 prefix = "";
300
301 copy = new(pid_t, n_pids);
302 if (!copy)
303 return -ENOMEM;
304
305 for (i = 0, j = 0; i < n_pids; i++) {
306 char *k;
307
308 r = cg_get_by_pid(controller, pids[i], &k);
309 if (r < 0) {
310 free(copy);
311 return r;
312 }
313
314 if (path_startswith(k, path))
315 continue;
316
317 copy[j++] = pids[i];
318 }
319
9bdbc2e2 320 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
b69d29ce
LP
321
322 free(copy);
323 return 0;
324}
325
9bdbc2e2 326int 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) {
b69d29ce
LP
327 int r;
328
329 assert(controller);
330 assert(path);
331
9bdbc2e2 332 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
b69d29ce
LP
333 if (r < 0)
334 return r;
335
9bdbc2e2 336 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
b69d29ce
LP
337}
338
9bdbc2e2 339int 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) {
b69d29ce 340 int r;
b08121d0 341 _cleanup_free_ char *controller = NULL, *path = NULL;
b69d29ce
LP
342
343 assert(spec);
344
345 r = cg_split_spec(spec, &controller, &path);
346 if (r < 0)
347 return r;
348
9bdbc2e2 349 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
b69d29ce 350}