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