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