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