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