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