]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-show.c
Merge pull request #2828 from mineo/run-help
[thirdparty/systemd.git] / src / shared / cgroup-show.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <dirent.h>
21 #include <errno.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "alloc-util.h"
28 #include "cgroup-show.h"
29 #include "cgroup-util.h"
30 #include "fd-util.h"
31 #include "formats-util.h"
32 #include "locale-util.h"
33 #include "macro.h"
34 #include "output-mode.h"
35 #include "path-util.h"
36 #include "process-util.h"
37 #include "string-util.h"
38 #include "terminal-util.h"
39
40 static int compare(const void *a, const void *b) {
41 const pid_t *p = a, *q = b;
42
43 if (*p < *q)
44 return -1;
45 if (*p > *q)
46 return 1;
47 return 0;
48 }
49
50 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) {
51 unsigned i, j, pid_width;
52
53 if (n_pids == 0)
54 return;
55
56 qsort(pids, n_pids, sizeof(pid_t), compare);
57
58 /* Filter duplicates */
59 for (j = 0, i = 1; i < n_pids; i++) {
60 if (pids[i] == pids[j])
61 continue;
62 pids[++j] = pids[i];
63 }
64 n_pids = j + 1;
65 pid_width = DECIMAL_STR_WIDTH(pids[j]);
66
67 if (flags & OUTPUT_FULL_WIDTH)
68 n_columns = 0;
69 else {
70 if (n_columns > pid_width+2)
71 n_columns -= pid_width+2;
72 else
73 n_columns = 20;
74 }
75 for (i = 0; i < n_pids; i++) {
76 _cleanup_free_ char *t = NULL;
77
78 get_process_cmdline(pids[i], n_columns, true, &t);
79
80 if (extra)
81 printf("%s%s ", prefix, draw_special_char(DRAW_TRIANGULAR_BULLET));
82 else
83 printf("%s%s", prefix, draw_special_char(((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)));
84
85 printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
86 }
87 }
88
89
90 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
91 char *fn;
92 _cleanup_fclose_ FILE *f = NULL;
93 size_t n = 0, n_allocated = 0;
94 _cleanup_free_ pid_t *pids = NULL;
95 _cleanup_free_ char *p = NULL;
96 pid_t pid;
97 int r;
98
99 r = cg_mangle_path(path, &p);
100 if (r < 0)
101 return r;
102
103 fn = strjoina(p, "/cgroup.procs");
104 f = fopen(fn, "re");
105 if (!f)
106 return -errno;
107
108 while ((r = cg_read_pid(f, &pid)) > 0) {
109
110 if (!kernel_threads && is_kernel_thread(pid) > 0)
111 continue;
112
113 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
114 return -ENOMEM;
115
116 assert(n < n_allocated);
117 pids[n++] = pid;
118 }
119
120 if (r < 0)
121 return r;
122
123 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
124
125 return 0;
126 }
127
128 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
129 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
130 _cleanup_closedir_ DIR *d = NULL;
131 char *gn = NULL;
132 bool shown_pids = false;
133 int r;
134
135 assert(path);
136
137 if (n_columns <= 0)
138 n_columns = columns();
139
140 if (!prefix)
141 prefix = "";
142
143 r = cg_mangle_path(path, &fn);
144 if (r < 0)
145 return r;
146
147 d = opendir(fn);
148 if (!d)
149 return -errno;
150
151 while ((r = cg_read_subgroup(d, &gn)) > 0) {
152 _cleanup_free_ char *k = NULL;
153
154 k = strjoin(fn, "/", gn, NULL);
155 free(gn);
156 if (!k)
157 return -ENOMEM;
158
159 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
160 continue;
161
162 if (!shown_pids) {
163 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
164 shown_pids = true;
165 }
166
167 if (last) {
168 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last)));
169
170 if (!p1) {
171 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
172 if (!p1)
173 return -ENOMEM;
174 }
175
176 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
177 free(last);
178 }
179
180 last = k;
181 k = NULL;
182 }
183
184 if (r < 0)
185 return r;
186
187 if (!shown_pids)
188 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
189
190 if (last) {
191 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
192
193 if (!p2) {
194 p2 = strappend(prefix, " ");
195 if (!p2)
196 return -ENOMEM;
197 }
198
199 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
200 }
201
202 return 0;
203 }
204
205 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
206 _cleanup_free_ char *p = NULL;
207 int r;
208
209 assert(path);
210
211 r = cg_get_path(controller, path, NULL, &p);
212 if (r < 0)
213 return r;
214
215 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
216 }
217
218 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) {
219 _cleanup_free_ pid_t *copy = NULL;
220 unsigned i, j;
221 int r;
222
223 assert(path);
224
225 if (n_pids <= 0)
226 return 0;
227
228 if (n_columns <= 0)
229 n_columns = columns();
230
231 prefix = strempty(prefix);
232
233 copy = new(pid_t, n_pids);
234 if (!copy)
235 return -ENOMEM;
236
237 for (i = 0, j = 0; i < n_pids; i++) {
238 _cleanup_free_ char *k = NULL;
239
240 r = cg_pid_get_path(controller, pids[i], &k);
241 if (r < 0)
242 return r;
243
244 if (path_startswith(k, path))
245 continue;
246
247 copy[j++] = pids[i];
248 }
249
250 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
251
252 return 0;
253 }
254
255 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) {
256 int r;
257
258 assert(path);
259
260 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
261 if (r < 0)
262 return r;
263
264 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
265 }
266
267 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) {
268 _cleanup_free_ char *controller = NULL, *path = NULL;
269 int r;
270
271 assert(spec);
272
273 r = cg_split_spec(spec, &controller, &path);
274 if (r < 0)
275 return r;
276
277 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
278 }