]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cgroup-show.c
strv: multiple cleanups
[thirdparty/systemd.git] / src / shared / cgroup-show.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ab35fb1b
LP
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
5430f7f2
LP
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
ab35fb1b
LP
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
5430f7f2 16 Lesser General Public License for more details.
ab35fb1b 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
ab35fb1b
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
23#include <string.h>
fa776d8e
LP
24#include <dirent.h>
25#include <errno.h>
ab35fb1b
LP
26
27#include "util.h"
28#include "macro.h"
9eb977db 29#include "path-util.h"
c6c18be3 30#include "cgroup-util.h"
ab35fb1b
LP
31#include "cgroup-show.h"
32
33static 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
9bdbc2e2 43static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
4278aa27 44 unsigned i, m, pid_width;
b69d29ce
LP
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;
82da66fb 63 pid_width = DECIMAL_STR_WIDTH(biggest);
b69d29ce
LP
64
65 /* And sort */
a0551d26 66 qsort_safe(pids, n_pids, sizeof(pid_t), compare);
b69d29ce 67
b47d419c 68 if (flags & OUTPUT_FULL_WIDTH)
9bdbc2e2
LN
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 }
b69d29ce 76 for (i = 0; i < n_pids; i++) {
b47d419c 77 _cleanup_free_ char *t = NULL;
b69d29ce
LP
78
79 get_process_cmdline(pids[i], n_columns, true, &t);
80
45a5ff0d 81 printf("%s%s%*lu %s\n",
b69d29ce 82 prefix,
c339d977 83 draw_special_char(extra ? DRAW_TRIANGULAR_BULLET :
45a5ff0d 84 ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)),
4278aa27 85 pid_width,
b69d29ce
LP
86 (unsigned long) pids[i],
87 strna(t));
b69d29ce
LP
88 }
89}
90
91
9bdbc2e2 92static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
ab35fb1b 93 char *fn;
7027ff61 94 _cleanup_fclose_ FILE *f = NULL;
ab35fb1b 95 size_t n = 0, n_allocated = 0;
7027ff61 96 _cleanup_free_ pid_t *pids = NULL;
b47d419c 97 _cleanup_free_ char *p = NULL;
b69d29ce 98 pid_t pid;
fa776d8e 99 int r;
ab35fb1b 100
7027ff61 101 r = cg_mangle_path(path, &p);
b69d29ce 102 if (r < 0)
35d2e7ec 103 return r;
ab35fb1b 104
b47d419c 105 fn = strappenda(p, "/cgroup.procs");
fa776d8e 106 f = fopen(fn, "re");
ab35fb1b 107 if (!f)
fa776d8e 108 return -errno;
ab35fb1b 109
c6c18be3 110 while ((r = cg_read_pid(f, &pid)) > 0) {
ab35fb1b 111
1e5678d0
LP
112 if (!kernel_threads && is_kernel_thread(pid) > 0)
113 continue;
114
ab35fb1b
LP
115 if (n >= n_allocated) {
116 pid_t *npids;
117
118 n_allocated = MAX(16U, n*2U);
119
b69d29ce 120 npids = realloc(pids, sizeof(pid_t) * n_allocated);
7027ff61
LP
121 if (!npids)
122 return -ENOMEM;
ab35fb1b
LP
123
124 pids = npids;
125 }
126
127 assert(n < n_allocated);
c6c18be3 128 pids[n++] = pid;
ab35fb1b
LP
129 }
130
c6c18be3 131 if (r < 0)
7027ff61 132 return r;
c6c18be3 133
b69d29ce 134 if (n > 0)
9bdbc2e2 135 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
ab35fb1b 136
7027ff61 137 return 0;
fa776d8e
LP
138}
139
9bdbc2e2 140int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
7027ff61
LP
141 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
142 _cleanup_closedir_ DIR *d = NULL;
143 char *gn = NULL;
fa776d8e
LP
144 bool shown_pids = false;
145 int r;
146
b69d29ce
LP
147 assert(path);
148
fa776d8e
LP
149 if (n_columns <= 0)
150 n_columns = columns();
151
152 if (!prefix)
153 prefix = "";
154
7027ff61 155 r = cg_mangle_path(path, &fn);
c3175a7f 156 if (r < 0)
35d2e7ec 157 return r;
fa776d8e 158
c3175a7f 159 d = opendir(fn);
7027ff61 160 if (!d)
fa776d8e 161 return -errno;
fa776d8e 162
35d2e7ec 163 while ((r = cg_read_subgroup(d, &gn)) > 0) {
7027ff61 164 _cleanup_free_ char *k = NULL;
c3175a7f 165
7027ff61 166 k = strjoin(fn, "/", gn, NULL);
c3175a7f 167 free(gn);
7027ff61
LP
168 if (!k)
169 return -ENOMEM;
c3175a7f 170
7027ff61 171 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
c3175a7f 172 continue;
fa776d8e
LP
173
174 if (!shown_pids) {
9bdbc2e2 175 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
fa776d8e
LP
176 shown_pids = true;
177 }
178
179 if (last) {
45a5ff0d 180 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH),
2b6bf07d 181 basename(last));
fa776d8e 182
c3175a7f 183 if (!p1) {
45a5ff0d 184 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
7027ff61
LP
185 if (!p1)
186 return -ENOMEM;
c3175a7f 187 }
fa776d8e 188
9bdbc2e2 189 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
fa776d8e 190 free(last);
fa776d8e
LP
191 }
192
c3175a7f 193 last = k;
7027ff61 194 k = NULL;
fa776d8e
LP
195 }
196
35d2e7ec 197 if (r < 0)
7027ff61 198 return r;
35d2e7ec 199
fa776d8e 200 if (!shown_pids)
9bdbc2e2 201 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
fa776d8e
LP
202
203 if (last) {
45a5ff0d 204 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT),
2b6bf07d 205 basename(last));
fa776d8e 206
c3175a7f
LP
207 if (!p2) {
208 p2 = strappend(prefix, " ");
7027ff61
LP
209 if (!p2)
210 return -ENOMEM;
c3175a7f 211 }
fa776d8e 212
9bdbc2e2 213 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
fa776d8e
LP
214 }
215
7027ff61 216 return 0;
ab35fb1b 217}
35d2e7ec 218
9bdbc2e2 219int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
7027ff61 220 _cleanup_free_ char *p = NULL;
35d2e7ec
LP
221 int r;
222
35d2e7ec
LP
223 assert(path);
224
1e5678d0
LP
225 r = cg_get_path(controller, path, NULL, &p);
226 if (r < 0)
35d2e7ec
LP
227 return r;
228
7027ff61 229 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
35d2e7ec 230}
b69d29ce 231
9bdbc2e2 232static 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) {
7fd1b19b 233 _cleanup_free_ pid_t *copy = NULL;
b69d29ce
LP
234 unsigned i, j;
235 int r;
236
b69d29ce
LP
237 assert(path);
238
239 if (n_pids <= 0)
240 return 0;
241
242 if (n_columns <= 0)
243 n_columns = columns();
244
7027ff61 245 prefix = strempty(prefix);
b69d29ce
LP
246
247 copy = new(pid_t, n_pids);
248 if (!copy)
249 return -ENOMEM;
250
251 for (i = 0, j = 0; i < n_pids; i++) {
7fd1b19b 252 _cleanup_free_ char *k = NULL;
b69d29ce 253
7027ff61 254 r = cg_pid_get_path(controller, pids[i], &k);
050fbdb8 255 if (r < 0)
b69d29ce 256 return r;
b69d29ce
LP
257
258 if (path_startswith(k, path))
259 continue;
260
261 copy[j++] = pids[i];
262 }
263
9bdbc2e2 264 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
b69d29ce 265
b69d29ce
LP
266 return 0;
267}
268
9bdbc2e2 269int 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) {
b69d29ce
LP
270 int r;
271
b69d29ce
LP
272 assert(path);
273
9bdbc2e2 274 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
b69d29ce
LP
275 if (r < 0)
276 return r;
277
9bdbc2e2 278 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
b69d29ce
LP
279}
280
9bdbc2e2 281int 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) {
b08121d0 282 _cleanup_free_ char *controller = NULL, *path = NULL;
7027ff61 283 int r;
b69d29ce
LP
284
285 assert(spec);
286
287 r = cg_split_spec(spec, &controller, &path);
288 if (r < 0)
289 return r;
290
9bdbc2e2 291 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
b69d29ce 292}