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