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