]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
Fix bad assert in show_pid_array
[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_safe(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 _cleanup_free_ 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 }
90
91
92 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
93 char *fn;
94 _cleanup_fclose_ FILE *f = NULL;
95 size_t n = 0, n_allocated = 0;
96 _cleanup_free_ pid_t *pids = NULL;
97 _cleanup_free_ char *p = NULL;
98 pid_t pid;
99 int r;
100
101 r = cg_mangle_path(path, &p);
102 if (r < 0)
103 return r;
104
105 fn = strappenda(p, "/cgroup.procs");
106 f = fopen(fn, "re");
107 if (!f)
108 return -errno;
109
110 while ((r = cg_read_pid(f, &pid)) > 0) {
111
112 if (!kernel_threads && is_kernel_thread(pid) > 0)
113 continue;
114
115 if (n >= n_allocated) {
116 pid_t *npids;
117
118 n_allocated = MAX(16U, n*2U);
119
120 npids = realloc(pids, sizeof(pid_t) * n_allocated);
121 if (!npids)
122 return -ENOMEM;
123
124 pids = npids;
125 }
126
127 assert(n < n_allocated);
128 pids[n++] = pid;
129 }
130
131 if (r < 0)
132 return r;
133
134 if (n > 0)
135 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
136
137 return 0;
138 }
139
140 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
141 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
142 _cleanup_closedir_ DIR *d = NULL;
143 char *gn = NULL;
144 bool shown_pids = false;
145 int r;
146
147 assert(path);
148
149 if (n_columns <= 0)
150 n_columns = columns();
151
152 if (!prefix)
153 prefix = "";
154
155 r = cg_mangle_path(path, &fn);
156 if (r < 0)
157 return r;
158
159 d = opendir(fn);
160 if (!d)
161 return -errno;
162
163 while ((r = cg_read_subgroup(d, &gn)) > 0) {
164 _cleanup_free_ char *k = NULL;
165
166 k = strjoin(fn, "/", gn, NULL);
167 free(gn);
168 if (!k)
169 return -ENOMEM;
170
171 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
172 continue;
173
174 if (!shown_pids) {
175 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
176 shown_pids = true;
177 }
178
179 if (last) {
180 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
181 path_get_file_name(last));
182
183 if (!p1) {
184 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
185 if (!p1)
186 return -ENOMEM;
187 }
188
189 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
190 free(last);
191 }
192
193 last = k;
194 k = NULL;
195 }
196
197 if (r < 0)
198 return r;
199
200 if (!shown_pids)
201 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
202
203 if (last) {
204 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
205 path_get_file_name(last));
206
207 if (!p2) {
208 p2 = strappend(prefix, " ");
209 if (!p2)
210 return -ENOMEM;
211 }
212
213 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
214 }
215
216 return 0;
217 }
218
219 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
220 _cleanup_free_ char *p = NULL;
221 int r;
222
223 assert(path);
224
225 r = cg_get_path(controller, path, NULL, &p);
226 if (r < 0)
227 return r;
228
229 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
230 }
231
232 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) {
233 _cleanup_free_ pid_t *copy = NULL;
234 unsigned i, j;
235 int r;
236
237 assert(path);
238
239 if (n_pids <= 0)
240 return 0;
241
242 if (n_columns <= 0)
243 n_columns = columns();
244
245 prefix = strempty(prefix);
246
247 copy = new(pid_t, n_pids);
248 if (!copy)
249 return -ENOMEM;
250
251 for (i = 0, j = 0; i < n_pids; i++) {
252 _cleanup_free_ char *k = NULL;
253
254 r = cg_pid_get_path(controller, pids[i], &k);
255 if (r < 0)
256 return r;
257
258 if (path_startswith(k, path))
259 continue;
260
261 copy[j++] = pids[i];
262 }
263
264 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
265
266 return 0;
267 }
268
269 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) {
270 int r;
271
272 assert(path);
273
274 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
275 if (r < 0)
276 return r;
277
278 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
279 }
280
281 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) {
282 _cleanup_free_ char *controller = NULL, *path = NULL;
283 int r;
284
285 assert(spec);
286
287 r = cg_split_spec(spec, &controller, &path);
288 if (r < 0)
289 return r;
290
291 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
292 }