]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
move _cleanup_ attribute in front of the type
[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 "path-util.h"
30 #include "cgroup-util.h"
31 #include "cgroup-show.h"
32
33 static 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
43 static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
44 unsigned i, m, pid_width;
45 pid_t biggest = 0;
46
47 /* Filter duplicates */
48 m = 0;
49 for (i = 0; i < n_pids; i++) {
50 unsigned j;
51
52 if (pids[i] > biggest)
53 biggest = pids[i];
54
55 for (j = i+1; j < n_pids; j++)
56 if (pids[i] == pids[j])
57 break;
58
59 if (j >= n_pids)
60 pids[m++] = pids[i];
61 }
62 n_pids = m;
63 pid_width = DECIMAL_STR_WIDTH(biggest);
64
65 /* And sort */
66 qsort(pids, n_pids, sizeof(pid_t), compare);
67
68 if(flags & OUTPUT_FULL_WIDTH)
69 n_columns = 0;
70 else {
71 if (n_columns > pid_width+2)
72 n_columns -= pid_width+2;
73 else
74 n_columns = 20;
75 }
76 for (i = 0; i < n_pids; i++) {
77 char *t = NULL;
78
79 get_process_cmdline(pids[i], n_columns, true, &t);
80
81 printf("%s%s%*lu %s\n",
82 prefix,
83 draw_special_char(extra ? DRAW_TRIANGULAR_BULLET :
84 ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)),
85 pid_width,
86 (unsigned long) pids[i],
87 strna(t));
88
89 free(t);
90 }
91 }
92
93
94 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
95 char *fn;
96 _cleanup_fclose_ FILE *f = NULL;
97 size_t n = 0, n_allocated = 0;
98 _cleanup_free_ pid_t *pids = NULL;
99 char *p = NULL;
100 pid_t pid;
101 int r;
102
103 r = cg_mangle_path(path, &p);
104 if (r < 0)
105 return r;
106
107 fn = strappend(p, "/cgroup.procs");
108 free(p);
109 if (!fn)
110 return -ENOMEM;
111
112 f = fopen(fn, "re");
113 free(fn);
114 if (!f)
115 return -errno;
116
117 while ((r = cg_read_pid(f, &pid)) > 0) {
118
119 if (!kernel_threads && is_kernel_thread(pid) > 0)
120 continue;
121
122 if (n >= n_allocated) {
123 pid_t *npids;
124
125 n_allocated = MAX(16U, n*2U);
126
127 npids = realloc(pids, sizeof(pid_t) * n_allocated);
128 if (!npids)
129 return -ENOMEM;
130
131 pids = npids;
132 }
133
134 assert(n < n_allocated);
135 pids[n++] = pid;
136 }
137
138 if (r < 0)
139 return r;
140
141 if (n > 0)
142 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
143
144 return 0;
145 }
146
147 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
148 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
149 _cleanup_closedir_ DIR *d = NULL;
150 char *gn = NULL;
151 bool shown_pids = false;
152 int r;
153
154 assert(path);
155
156 if (n_columns <= 0)
157 n_columns = columns();
158
159 if (!prefix)
160 prefix = "";
161
162 r = cg_mangle_path(path, &fn);
163 if (r < 0)
164 return r;
165
166 d = opendir(fn);
167 if (!d)
168 return -errno;
169
170 while ((r = cg_read_subgroup(d, &gn)) > 0) {
171 _cleanup_free_ char *k = NULL;
172
173 k = strjoin(fn, "/", gn, NULL);
174 free(gn);
175 if (!k)
176 return -ENOMEM;
177
178 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
179 continue;
180
181 if (!shown_pids) {
182 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
183 shown_pids = true;
184 }
185
186 if (last) {
187 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
188 path_get_file_name(last));
189
190 if (!p1) {
191 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
192 if (!p1)
193 return -ENOMEM;
194 }
195
196 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
197 free(last);
198 }
199
200 last = k;
201 k = NULL;
202 }
203
204 if (r < 0)
205 return r;
206
207 if (!shown_pids)
208 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
209
210 if (last) {
211 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
212 path_get_file_name(last));
213
214 if (!p2) {
215 p2 = strappend(prefix, " ");
216 if (!p2)
217 return -ENOMEM;
218 }
219
220 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
221 }
222
223 return 0;
224 }
225
226 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
227 _cleanup_free_ char *p = NULL;
228 int r;
229
230 assert(path);
231
232 r = cg_get_path(controller, path, NULL, &p);
233 if (r < 0)
234 return r;
235
236 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
237 }
238
239 static 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) {
240 _cleanup_free_ pid_t *copy = NULL;
241 unsigned i, j;
242 int r;
243
244 assert(controller);
245 assert(path);
246
247 if (n_pids <= 0)
248 return 0;
249
250 if (n_columns <= 0)
251 n_columns = columns();
252
253 prefix = strempty(prefix);
254
255 copy = new(pid_t, n_pids);
256 if (!copy)
257 return -ENOMEM;
258
259 for (i = 0, j = 0; i < n_pids; i++) {
260 _cleanup_free_ char *k = NULL;
261
262 r = cg_pid_get_path(controller, pids[i], &k);
263 if (r < 0)
264 return r;
265
266 if (path_startswith(k, path))
267 continue;
268
269 copy[j++] = pids[i];
270 }
271
272 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
273
274 return 0;
275 }
276
277 int 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) {
278 int r;
279
280 assert(path);
281
282 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
283 if (r < 0)
284 return r;
285
286 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
287 }
288
289 int 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) {
290 _cleanup_free_ char *controller = NULL, *path = NULL;
291 int r;
292
293 assert(spec);
294
295 r = cg_split_spec(spec, &controller, &path);
296 if (r < 0)
297 return r;
298
299 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
300 }