]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cgroup-show.c
Merge pull request #2719 from evverx/add-test-to-makefile
[thirdparty/systemd.git] / src / shared / cgroup-show.c
CommitLineData
ab35fb1b
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
ab35fb1b
LP
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 14 Lesser General Public License for more details.
ab35fb1b 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
ab35fb1b
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
fa776d8e
LP
20#include <dirent.h>
21#include <errno.h>
a8fbdf54 22#include <stddef.h>
07630cea 23#include <stdio.h>
a8fbdf54 24#include <stdlib.h>
07630cea 25#include <string.h>
ab35fb1b 26
b5efdb8a 27#include "alloc-util.h"
3ffd4af2 28#include "cgroup-show.h"
07630cea 29#include "cgroup-util.h"
3ffd4af2 30#include "fd-util.h"
6482f626 31#include "formats-util.h"
8752c575 32#include "locale-util.h"
ab35fb1b 33#include "macro.h"
a8fbdf54 34#include "output-mode.h"
9eb977db 35#include "path-util.h"
07630cea
LP
36#include "process-util.h"
37#include "string-util.h"
288a74cc 38#include "terminal-util.h"
ab35fb1b
LP
39
40static int compare(const void *a, const void *b) {
41 const pid_t *p = a, *q = b;
42
43 if (*p < *q)
44 return -1;
45 if (*p > *q)
46 return 1;
47 return 0;
48}
49
3da7a50f
ZJS
50static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
51 unsigned i, j, pid_width;
b69d29ce 52
da41abc5 53 if (n_pids == 0)
3637713a
LP
54 return;
55
3da7a50f 56 qsort(pids, n_pids, sizeof(pid_t), compare);
b69d29ce 57
3da7a50f
ZJS
58 /* Filter duplicates */
59 for (j = 0, i = 1; i < n_pids; i++) {
60 if (pids[i] == pids[j])
61 continue;
62 pids[++j] = pids[i];
b69d29ce 63 }
3da7a50f
ZJS
64 n_pids = j + 1;
65 pid_width = DECIMAL_STR_WIDTH(pids[j]);
b69d29ce 66
b47d419c 67 if (flags & OUTPUT_FULL_WIDTH)
9bdbc2e2
LN
68 n_columns = 0;
69 else {
70 if (n_columns > pid_width+2)
71 n_columns -= pid_width+2;
72 else
73 n_columns = 20;
74 }
b69d29ce 75 for (i = 0; i < n_pids; i++) {
b47d419c 76 _cleanup_free_ char *t = NULL;
b69d29ce
LP
77
78 get_process_cmdline(pids[i], n_columns, true, &t);
79
6b01f1d3
LP
80 if (extra)
81 printf("%s%s ", prefix, draw_special_char(DRAW_TRIANGULAR_BULLET));
82 else
83 printf("%s%s", prefix, draw_special_char(((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)));
84
3da7a50f 85 printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
b69d29ce
LP
86 }
87}
88
89
9bdbc2e2 90static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
ab35fb1b 91 char *fn;
7027ff61 92 _cleanup_fclose_ FILE *f = NULL;
ab35fb1b 93 size_t n = 0, n_allocated = 0;
7027ff61 94 _cleanup_free_ pid_t *pids = NULL;
b47d419c 95 _cleanup_free_ char *p = NULL;
b69d29ce 96 pid_t pid;
fa776d8e 97 int r;
ab35fb1b 98
7027ff61 99 r = cg_mangle_path(path, &p);
b69d29ce 100 if (r < 0)
35d2e7ec 101 return r;
ab35fb1b 102
63c372cb 103 fn = strjoina(p, "/cgroup.procs");
fa776d8e 104 f = fopen(fn, "re");
ab35fb1b 105 if (!f)
fa776d8e 106 return -errno;
ab35fb1b 107
c6c18be3 108 while ((r = cg_read_pid(f, &pid)) > 0) {
ab35fb1b 109
1e5678d0
LP
110 if (!kernel_threads && is_kernel_thread(pid) > 0)
111 continue;
112
3da7a50f
ZJS
113 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
114 return -ENOMEM;
ab35fb1b
LP
115
116 assert(n < n_allocated);
c6c18be3 117 pids[n++] = pid;
ab35fb1b
LP
118 }
119
c6c18be3 120 if (r < 0)
7027ff61 121 return r;
c6c18be3 122
da41abc5 123 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
ab35fb1b 124
7027ff61 125 return 0;
fa776d8e
LP
126}
127
9bdbc2e2 128int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
7027ff61
LP
129 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
130 _cleanup_closedir_ DIR *d = NULL;
131 char *gn = NULL;
fa776d8e
LP
132 bool shown_pids = false;
133 int r;
134
b69d29ce
LP
135 assert(path);
136
fa776d8e
LP
137 if (n_columns <= 0)
138 n_columns = columns();
139
140 if (!prefix)
141 prefix = "";
142
7027ff61 143 r = cg_mangle_path(path, &fn);
c3175a7f 144 if (r < 0)
35d2e7ec 145 return r;
fa776d8e 146
c3175a7f 147 d = opendir(fn);
7027ff61 148 if (!d)
fa776d8e 149 return -errno;
fa776d8e 150
35d2e7ec 151 while ((r = cg_read_subgroup(d, &gn)) > 0) {
7027ff61 152 _cleanup_free_ char *k = NULL;
c3175a7f 153
7027ff61 154 k = strjoin(fn, "/", gn, NULL);
c3175a7f 155 free(gn);
7027ff61
LP
156 if (!k)
157 return -ENOMEM;
c3175a7f 158
6f883237 159 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
c3175a7f 160 continue;
fa776d8e
LP
161
162 if (!shown_pids) {
9bdbc2e2 163 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
fa776d8e
LP
164 shown_pids = true;
165 }
166
167 if (last) {
3d9495a8 168 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last)));
fa776d8e 169
c3175a7f 170 if (!p1) {
6b01f1d3 171 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
7027ff61
LP
172 if (!p1)
173 return -ENOMEM;
c3175a7f 174 }
fa776d8e 175
9bdbc2e2 176 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
fa776d8e 177 free(last);
fa776d8e
LP
178 }
179
c3175a7f 180 last = k;
7027ff61 181 k = NULL;
fa776d8e
LP
182 }
183
35d2e7ec 184 if (r < 0)
7027ff61 185 return r;
35d2e7ec 186
fa776d8e 187 if (!shown_pids)
9bdbc2e2 188 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
fa776d8e
LP
189
190 if (last) {
3d9495a8 191 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
fa776d8e 192
c3175a7f
LP
193 if (!p2) {
194 p2 = strappend(prefix, " ");
7027ff61
LP
195 if (!p2)
196 return -ENOMEM;
c3175a7f 197 }
fa776d8e 198
9bdbc2e2 199 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
fa776d8e
LP
200 }
201
7027ff61 202 return 0;
ab35fb1b 203}
35d2e7ec 204
9bdbc2e2 205int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
7027ff61 206 _cleanup_free_ char *p = NULL;
35d2e7ec
LP
207 int r;
208
35d2e7ec
LP
209 assert(path);
210
1e5678d0
LP
211 r = cg_get_path(controller, path, NULL, &p);
212 if (r < 0)
35d2e7ec
LP
213 return r;
214
7027ff61 215 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
35d2e7ec 216}
b69d29ce 217
9bdbc2e2 218static 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) {
7fd1b19b 219 _cleanup_free_ pid_t *copy = NULL;
b69d29ce
LP
220 unsigned i, j;
221 int r;
222
b69d29ce
LP
223 assert(path);
224
225 if (n_pids <= 0)
226 return 0;
227
228 if (n_columns <= 0)
229 n_columns = columns();
230
7027ff61 231 prefix = strempty(prefix);
b69d29ce
LP
232
233 copy = new(pid_t, n_pids);
234 if (!copy)
235 return -ENOMEM;
236
237 for (i = 0, j = 0; i < n_pids; i++) {
7fd1b19b 238 _cleanup_free_ char *k = NULL;
b69d29ce 239
7027ff61 240 r = cg_pid_get_path(controller, pids[i], &k);
050fbdb8 241 if (r < 0)
b69d29ce 242 return r;
b69d29ce
LP
243
244 if (path_startswith(k, path))
245 continue;
246
247 copy[j++] = pids[i];
248 }
249
9bdbc2e2 250 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
b69d29ce 251
b69d29ce
LP
252 return 0;
253}
254
9bdbc2e2 255int 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
256 int r;
257
b69d29ce
LP
258 assert(path);
259
9bdbc2e2 260 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
b69d29ce
LP
261 if (r < 0)
262 return r;
263
9bdbc2e2 264 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
b69d29ce
LP
265}
266
9bdbc2e2 267int 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) {
b08121d0 268 _cleanup_free_ char *controller = NULL, *path = NULL;
7027ff61 269 int r;
b69d29ce
LP
270
271 assert(spec);
272
273 r = cg_split_spec(spec, &controller, &path);
274 if (r < 0)
275 return r;
276
9bdbc2e2 277 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
b69d29ce 278}