chiark / gitweb /
a59f7c2a9e2c8daf03f4d9e6f5a32b9710f42d6d
[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 <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 "macro.h"
30 #include "path-util.h"
31 #include "cgroup-util.h"
32 #include "cgroup-show.h"
33 #include "terminal-util.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) > 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), cg_unescape(basename(last)));
164
165                         if (!p1) {
166                                 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
167                                 if (!p1)
168                                         return -ENOMEM;
169                         }
170
171                         show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
172                         free(last);
173                 }
174
175                 last = k;
176                 k = NULL;
177         }
178
179         if (r < 0)
180                 return r;
181
182         if (!shown_pids)
183                 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
184
185         if (last) {
186                 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(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 /// UNNEEDED by elogind
263 #if 0
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 }
276 #endif // 0