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