chiark / gitweb /
0f263e958c5cb644d96068bba12bf5bf50f6d50d
[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 "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 }