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