]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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-util.h"
28 #include "formats-util.h"
29 #include "macro.h"
30 #include "path-util.h"
31 #include "process-util.h"
32 #include "string-util.h"
33 #include "terminal-util.h"
34 #include "util.h"
35 #include "cgroup-show.h"
36
37 static int compare(const void *a, const void *b) {
38 const pid_t *p = a, *q = b;
39
40 if (*p < *q)
41 return -1;
42 if (*p > *q)
43 return 1;
44 return 0;
45 }
46
47 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) {
48 unsigned i, j, pid_width;
49
50 if (n_pids == 0)
51 return;
52
53 qsort(pids, n_pids, sizeof(pid_t), compare);
54
55 /* Filter duplicates */
56 for (j = 0, i = 1; i < n_pids; i++) {
57 if (pids[i] == pids[j])
58 continue;
59 pids[++j] = pids[i];
60 }
61 n_pids = j + 1;
62 pid_width = DECIMAL_STR_WIDTH(pids[j]);
63
64 if (flags & OUTPUT_FULL_WIDTH)
65 n_columns = 0;
66 else {
67 if (n_columns > pid_width+2)
68 n_columns -= pid_width+2;
69 else
70 n_columns = 20;
71 }
72 for (i = 0; i < n_pids; i++) {
73 _cleanup_free_ char *t = NULL;
74
75 get_process_cmdline(pids[i], n_columns, true, &t);
76
77 if (extra)
78 printf("%s%s ", prefix, draw_special_char(DRAW_TRIANGULAR_BULLET));
79 else
80 printf("%s%s", prefix, draw_special_char(((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)));
81
82 printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
83 }
84 }
85
86
87 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
88 char *fn;
89 _cleanup_fclose_ FILE *f = NULL;
90 size_t n = 0, n_allocated = 0;
91 _cleanup_free_ pid_t *pids = NULL;
92 _cleanup_free_ char *p = NULL;
93 pid_t pid;
94 int r;
95
96 r = cg_mangle_path(path, &p);
97 if (r < 0)
98 return r;
99
100 fn = strjoina(p, "/cgroup.procs");
101 f = fopen(fn, "re");
102 if (!f)
103 return -errno;
104
105 while ((r = cg_read_pid(f, &pid)) > 0) {
106
107 if (!kernel_threads && is_kernel_thread(pid) > 0)
108 continue;
109
110 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
111 return -ENOMEM;
112
113 assert(n < n_allocated);
114 pids[n++] = pid;
115 }
116
117 if (r < 0)
118 return r;
119
120 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
121
122 return 0;
123 }
124
125 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
126 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
127 _cleanup_closedir_ DIR *d = NULL;
128 char *gn = NULL;
129 bool shown_pids = false;
130 int r;
131
132 assert(path);
133
134 if (n_columns <= 0)
135 n_columns = columns();
136
137 if (!prefix)
138 prefix = "";
139
140 r = cg_mangle_path(path, &fn);
141 if (r < 0)
142 return r;
143
144 d = opendir(fn);
145 if (!d)
146 return -errno;
147
148 while ((r = cg_read_subgroup(d, &gn)) > 0) {
149 _cleanup_free_ char *k = NULL;
150
151 k = strjoin(fn, "/", gn, NULL);
152 free(gn);
153 if (!k)
154 return -ENOMEM;
155
156 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
157 continue;
158
159 if (!shown_pids) {
160 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
161 shown_pids = true;
162 }
163
164 if (last) {
165 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last)));
166
167 if (!p1) {
168 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
169 if (!p1)
170 return -ENOMEM;
171 }
172
173 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
174 free(last);
175 }
176
177 last = k;
178 k = NULL;
179 }
180
181 if (r < 0)
182 return r;
183
184 if (!shown_pids)
185 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
186
187 if (last) {
188 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(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 }