]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cgroup-show.c
util-lib: split out allocation calls into alloc-util.[ch]
[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
fa776d8e
LP
22#include <dirent.h>
23#include <errno.h>
07630cea
LP
24#include <stdio.h>
25#include <string.h>
ab35fb1b 26
b5efdb8a 27#include "alloc-util.h"
3ffd4af2 28#include "cgroup-show.h"
07630cea 29#include "cgroup-util.h"
3ffd4af2 30#include "fd-util.h"
6482f626 31#include "formats-util.h"
8752c575 32#include "locale-util.h"
ab35fb1b 33#include "macro.h"
9eb977db 34#include "path-util.h"
07630cea
LP
35#include "process-util.h"
36#include "string-util.h"
288a74cc 37#include "terminal-util.h"
07630cea 38#include "util.h"
ab35fb1b
LP
39
40static 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
3da7a50f
ZJS
50static 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;
b69d29ce 52
da41abc5 53 if (n_pids == 0)
3637713a
LP
54 return;
55
3da7a50f 56 qsort(pids, n_pids, sizeof(pid_t), compare);
b69d29ce 57
3da7a50f
ZJS
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];
b69d29ce 63 }
3da7a50f
ZJS
64 n_pids = j + 1;
65 pid_width = DECIMAL_STR_WIDTH(pids[j]);
b69d29ce 66
b47d419c 67 if (flags & OUTPUT_FULL_WIDTH)
9bdbc2e2
LN
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 }
b69d29ce 75 for (i = 0; i < n_pids; i++) {
b47d419c 76 _cleanup_free_ char *t = NULL;
b69d29ce
LP
77
78 get_process_cmdline(pids[i], n_columns, true, &t);
79
6b01f1d3
LP
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
3da7a50f 85 printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
b69d29ce
LP
86 }
87}
88
89
9bdbc2e2 90static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
ab35fb1b 91 char *fn;
7027ff61 92 _cleanup_fclose_ FILE *f = NULL;
ab35fb1b 93 size_t n = 0, n_allocated = 0;
7027ff61 94 _cleanup_free_ pid_t *pids = NULL;
b47d419c 95 _cleanup_free_ char *p = NULL;
b69d29ce 96 pid_t pid;
fa776d8e 97 int r;
ab35fb1b 98
7027ff61 99 r = cg_mangle_path(path, &p);
b69d29ce 100 if (r < 0)
35d2e7ec 101 return r;
ab35fb1b 102
63c372cb 103 fn = strjoina(p, "/cgroup.procs");
fa776d8e 104 f = fopen(fn, "re");
ab35fb1b 105 if (!f)
fa776d8e 106 return -errno;
ab35fb1b 107
c6c18be3 108 while ((r = cg_read_pid(f, &pid)) > 0) {
ab35fb1b 109
1e5678d0
LP
110 if (!kernel_threads && is_kernel_thread(pid) > 0)
111 continue;
112
3da7a50f
ZJS
113 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
114 return -ENOMEM;
ab35fb1b
LP
115
116 assert(n < n_allocated);
c6c18be3 117 pids[n++] = pid;
ab35fb1b
LP
118 }
119
c6c18be3 120 if (r < 0)
7027ff61 121 return r;
c6c18be3 122
da41abc5 123 show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
ab35fb1b 124
7027ff61 125 return 0;
fa776d8e
LP
126}
127
9bdbc2e2 128int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
7027ff61
LP
129 _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
130 _cleanup_closedir_ DIR *d = NULL;
131 char *gn = NULL;
fa776d8e
LP
132 bool shown_pids = false;
133 int r;
134
b69d29ce
LP
135 assert(path);
136
fa776d8e
LP
137 if (n_columns <= 0)
138 n_columns = columns();
139
140 if (!prefix)
141 prefix = "";
142
7027ff61 143 r = cg_mangle_path(path, &fn);
c3175a7f 144 if (r < 0)
35d2e7ec 145 return r;
fa776d8e 146
c3175a7f 147 d = opendir(fn);
7027ff61 148 if (!d)
fa776d8e 149 return -errno;
fa776d8e 150
35d2e7ec 151 while ((r = cg_read_subgroup(d, &gn)) > 0) {
7027ff61 152 _cleanup_free_ char *k = NULL;
c3175a7f 153
7027ff61 154 k = strjoin(fn, "/", gn, NULL);
c3175a7f 155 free(gn);
7027ff61
LP
156 if (!k)
157 return -ENOMEM;
c3175a7f 158
6f883237 159 if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
c3175a7f 160 continue;
fa776d8e
LP
161
162 if (!shown_pids) {
9bdbc2e2 163 show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
fa776d8e
LP
164 shown_pids = true;
165 }
166
167 if (last) {
3d9495a8 168 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last)));
fa776d8e 169
c3175a7f 170 if (!p1) {
6b01f1d3 171 p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
7027ff61
LP
172 if (!p1)
173 return -ENOMEM;
c3175a7f 174 }
fa776d8e 175
9bdbc2e2 176 show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
fa776d8e 177 free(last);
fa776d8e
LP
178 }
179
c3175a7f 180 last = k;
7027ff61 181 k = NULL;
fa776d8e
LP
182 }
183
35d2e7ec 184 if (r < 0)
7027ff61 185 return r;
35d2e7ec 186
fa776d8e 187 if (!shown_pids)
9bdbc2e2 188 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
fa776d8e
LP
189
190 if (last) {
3d9495a8 191 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
fa776d8e 192
c3175a7f
LP
193 if (!p2) {
194 p2 = strappend(prefix, " ");
7027ff61
LP
195 if (!p2)
196 return -ENOMEM;
c3175a7f 197 }
fa776d8e 198
9bdbc2e2 199 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
fa776d8e
LP
200 }
201
7027ff61 202 return 0;
ab35fb1b 203}
35d2e7ec 204
9bdbc2e2 205int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
7027ff61 206 _cleanup_free_ char *p = NULL;
35d2e7ec
LP
207 int r;
208
35d2e7ec
LP
209 assert(path);
210
1e5678d0
LP
211 r = cg_get_path(controller, path, NULL, &p);
212 if (r < 0)
35d2e7ec
LP
213 return r;
214
7027ff61 215 return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
35d2e7ec 216}
b69d29ce 217
9bdbc2e2 218static 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 219 _cleanup_free_ pid_t *copy = NULL;
b69d29ce
LP
220 unsigned i, j;
221 int r;
222
b69d29ce
LP
223 assert(path);
224
225 if (n_pids <= 0)
226 return 0;
227
228 if (n_columns <= 0)
229 n_columns = columns();
230
7027ff61 231 prefix = strempty(prefix);
b69d29ce
LP
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++) {
7fd1b19b 238 _cleanup_free_ char *k = NULL;
b69d29ce 239
7027ff61 240 r = cg_pid_get_path(controller, pids[i], &k);
050fbdb8 241 if (r < 0)
b69d29ce 242 return r;
b69d29ce
LP
243
244 if (path_startswith(k, path))
245 continue;
246
247 copy[j++] = pids[i];
248 }
249
9bdbc2e2 250 show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
b69d29ce 251
b69d29ce
LP
252 return 0;
253}
254
9bdbc2e2 255int 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
256 int r;
257
b69d29ce
LP
258 assert(path);
259
9bdbc2e2 260 r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
b69d29ce
LP
261 if (r < 0)
262 return r;
263
9bdbc2e2 264 return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
b69d29ce
LP
265}
266
9bdbc2e2 267int 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 268 _cleanup_free_ char *controller = NULL, *path = NULL;
7027ff61 269 int r;
b69d29ce
LP
270
271 assert(spec);
272
273 r = cg_split_spec(spec, &controller, &path);
274 if (r < 0)
275 return r;
276
9bdbc2e2 277 return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
b69d29ce 278}