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