]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
Merge pull request #4510 from keszybz/tree-wide-cleanups
[thirdparty/systemd.git] / src / shared / cgroup-show.c
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
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
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
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <dirent.h>
21 #include <errno.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "alloc-util.h"
28 #include "cgroup-show.h"
29 #include "cgroup-util.h"
30 #include "fd-util.h"
31 #include "formats-util.h"
32 #include "locale-util.h"
33 #include "macro.h"
34 #include "output-mode.h"
35 #include "path-util.h"
36 #include "process-util.h"
37 #include "string-util.h"
38 #include "terminal-util.h"
39
40 static void show_pid_array(
41 pid_t pids[],
42 unsigned n_pids,
43 const char *prefix,
44 unsigned n_columns,
45 bool extra,
46 bool more,
47 OutputFlags flags) {
48
49 unsigned i, j, pid_width;
50
51 if (n_pids == 0)
52 return;
53
54 qsort(pids, n_pids, sizeof(pid_t), pid_compare_func);
55
56 /* Filter duplicates */
57 for (j = 0, i = 1; i < n_pids; i++) {
58 if (pids[i] == pids[j])
59 continue;
60 pids[++j] = pids[i];
61 }
62 n_pids = j + 1;
63 pid_width = DECIMAL_STR_WIDTH(pids[j]);
64
65 if (flags & OUTPUT_FULL_WIDTH)
66 n_columns = 0;
67 else {
68 if (n_columns > pid_width+2)
69 n_columns -= pid_width+2;
70 else
71 n_columns = 20;
72 }
73 for (i = 0; i < n_pids; i++) {
74 _cleanup_free_ char *t = NULL;
75
76 get_process_cmdline(pids[i], n_columns, true, &t);
77
78 if (extra)
79 printf("%s%s ", prefix, special_glyph(TRIANGULAR_BULLET));
80 else
81 printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? TREE_BRANCH : TREE_RIGHT)));
82
83 printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
84 }
85 }
86
87 static int show_cgroup_one_by_path(
88 const char *path,
89 const char *prefix,
90 unsigned n_columns,
91 bool more,
92 OutputFlags flags) {
93
94 char *fn;
95 _cleanup_fclose_ FILE *f = NULL;
96 size_t n = 0, n_allocated = 0;
97 _cleanup_free_ pid_t *pids = NULL;
98 _cleanup_free_ char *p = NULL;
99 pid_t pid;
100 int r;
101
102 r = cg_mangle_path(path, &p);
103 if (r < 0)
104 return r;
105
106 fn = strjoina(p, "/cgroup.procs");
107 f = fopen(fn, "re");
108 if (!f)
109 return -errno;
110
111 while ((r = cg_read_pid(f, &pid)) > 0) {
112
113 if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0)
114 continue;
115
116 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
117 return -ENOMEM;
118
119 assert(n < n_allocated);
120 pids[n++] = pid;
121 }
122
123 if (r < 0)
124 return r;
125
126 show_pid_array(pids, n, prefix, n_columns, false, more, flags);
127
128 return 0;
129 }
130
131 int show_cgroup_by_path(
132 const char *path,
133 const char *prefix,
134 unsigned n_columns,
135 OutputFlags flags) {
136
137 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
138 _cleanup_closedir_ DIR *d = NULL;
139 char *gn = NULL;
140 bool shown_pids = false;
141 int r;
142
143 assert(path);
144
145 if (n_columns <= 0)
146 n_columns = columns();
147
148 prefix = strempty(prefix);
149
150 r = cg_mangle_path(path, &fn);
151 if (r < 0)
152 return r;
153
154 d = opendir(fn);
155 if (!d)
156 return -errno;
157
158 while ((r = cg_read_subgroup(d, &gn)) > 0) {
159 _cleanup_free_ char *k = NULL;
160
161 k = strjoin(fn, "/", gn);
162 free(gn);
163 if (!k)
164 return -ENOMEM;
165
166 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
167 continue;
168
169 if (!shown_pids) {
170 show_cgroup_one_by_path(path, prefix, n_columns, true, flags);
171 shown_pids = true;
172 }
173
174 if (last) {
175 printf("%s%s%s\n", prefix, special_glyph(TREE_BRANCH), cg_unescape(basename(last)));
176
177 if (!p1) {
178 p1 = strappend(prefix, special_glyph(TREE_VERTICAL));
179 if (!p1)
180 return -ENOMEM;
181 }
182
183 show_cgroup_by_path(last, p1, n_columns-2, flags);
184 free(last);
185 }
186
187 last = k;
188 k = NULL;
189 }
190
191 if (r < 0)
192 return r;
193
194 if (!shown_pids)
195 show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags);
196
197 if (last) {
198 printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), cg_unescape(basename(last)));
199
200 if (!p2) {
201 p2 = strappend(prefix, " ");
202 if (!p2)
203 return -ENOMEM;
204 }
205
206 show_cgroup_by_path(last, p2, n_columns-2, flags);
207 }
208
209 return 0;
210 }
211
212 int show_cgroup(const char *controller,
213 const char *path,
214 const char *prefix,
215 unsigned n_columns,
216 OutputFlags flags) {
217 _cleanup_free_ char *p = NULL;
218 int r;
219
220 assert(path);
221
222 r = cg_get_path(controller, path, NULL, &p);
223 if (r < 0)
224 return r;
225
226 return show_cgroup_by_path(p, prefix, n_columns, flags);
227 }
228
229 static int show_extra_pids(
230 const char *controller,
231 const char *path,
232 const char *prefix,
233 unsigned n_columns,
234 const pid_t pids[],
235 unsigned n_pids,
236 OutputFlags flags) {
237
238 _cleanup_free_ pid_t *copy = NULL;
239 unsigned i, j;
240 int r;
241
242 assert(path);
243
244 if (n_pids <= 0)
245 return 0;
246
247 if (n_columns <= 0)
248 n_columns = columns();
249
250 prefix = strempty(prefix);
251
252 copy = new(pid_t, n_pids);
253 if (!copy)
254 return -ENOMEM;
255
256 for (i = 0, j = 0; i < n_pids; i++) {
257 _cleanup_free_ char *k = NULL;
258
259 r = cg_pid_get_path(controller, pids[i], &k);
260 if (r < 0)
261 return r;
262
263 if (path_startswith(k, path))
264 continue;
265
266 copy[j++] = pids[i];
267 }
268
269 show_pid_array(copy, j, prefix, n_columns, true, false, flags);
270
271 return 0;
272 }
273
274 int show_cgroup_and_extra(
275 const char *controller,
276 const char *path,
277 const char *prefix,
278 unsigned n_columns,
279 const pid_t extra_pids[],
280 unsigned n_extra_pids,
281 OutputFlags flags) {
282
283 int r;
284
285 assert(path);
286
287 r = show_cgroup(controller, path, prefix, n_columns, flags);
288 if (r < 0)
289 return r;
290
291 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
292 }
293
294 int show_cgroup_and_extra_by_spec(
295 const char *spec,
296 const char *prefix,
297 unsigned n_columns,
298 const pid_t extra_pids[],
299 unsigned n_extra_pids,
300 OutputFlags flags) {
301
302 _cleanup_free_ char *controller = NULL, *path = NULL;
303 int r;
304
305 assert(spec);
306
307 r = cg_split_spec(spec, &controller, &path);
308 if (r < 0)
309 return r;
310
311 return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
312 }