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