]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cgls/cgls.c
analyze security: fix recursive call of syscall_names_in_filter()
[thirdparty/systemd.git] / src / cgls / cgls.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
fa776d8e 2
fa776d8e
LP
3#include <errno.h>
4#include <getopt.h>
3f6fd1ba 5#include <stdio.h>
fa776d8e 6#include <string.h>
3f6fd1ba
LP
7#include <unistd.h>
8
9#include "sd-bus.h"
fa776d8e 10
b5efdb8a 11#include "alloc-util.h"
3f6fd1ba 12#include "bus-util.h"
fa776d8e 13#include "cgroup-show.h"
c6c18be3 14#include "cgroup-util.h"
3f6fd1ba 15#include "fileio.h"
fa776d8e 16#include "log.h"
88325bf6 17#include "main-func.h"
9bdbc2e2 18#include "output-mode.h"
3f6fd1ba
LP
19#include "pager.h"
20#include "path-util.h"
294bf0c3 21#include "pretty-print.h"
256c1eba 22#include "strv.h"
13be4979 23#include "unit-name.h"
3f6fd1ba 24#include "util.h"
1968a360 25
0221d68a 26static PagerFlags arg_pager_flags = 0;
1e5678d0 27static bool arg_kernel_threads = false;
c3175a7f 28static bool arg_all = false;
e7aa3f50
ZJS
29
30static enum {
31 SHOW_UNIT_NONE,
32 SHOW_UNIT_SYSTEM,
33 SHOW_UNIT_USER,
34} arg_show_unit = SHOW_UNIT_NONE;
256c1eba 35static char **arg_names = NULL;
e7aa3f50 36
9bdbc2e2 37static int arg_full = -1;
2428944e 38static const char* arg_machine = NULL;
fa776d8e 39
88325bf6
YW
40STATIC_DESTRUCTOR_REGISTER(arg_names, freep); /* don't free the strings */
41
37ec0fdd
LP
42static int help(void) {
43 _cleanup_free_ char *link = NULL;
44 int r;
45
46 r = terminal_urlify_man("systemd-cgls", "1", &link);
47 if (r < 0)
48 return log_oom();
49
fa776d8e
LP
50 printf("%s [OPTIONS...] [CGROUP...]\n\n"
51 "Recursively show control group contents.\n\n"
69fc152f 52 " -h --help Show this help\n"
c3175a7f 53 " --version Show package version\n"
1e5678d0 54 " --no-pager Do not pipe output into a pager\n"
c3175a7f 55 " -a --all Show all groups, including empty\n"
e7aa3f50
ZJS
56 " -u --unit Show the subtrees of specifified system units\n"
57 " --user-unit Show the subtrees of specifified user units\n"
98a6e132 58 " -l --full Do not ellipsize output\n"
38158b92 59 " -k Include kernel threads in output\n"
e049fa16 60 " -M --machine= Show container\n"
37ec0fdd
LP
61 "\nSee the %s for details.\n"
62 , program_invocation_short_name
63 , link
64 );
65
66 return 0;
fa776d8e
LP
67}
68
69static int parse_argv(int argc, char *argv[]) {
70
1968a360 71 enum {
c3175a7f 72 ARG_NO_PAGER = 0x100,
9bdbc2e2 73 ARG_VERSION,
e7aa3f50 74 ARG_USER_UNIT,
1968a360
LP
75 };
76
fa776d8e 77 static const struct option options[] = {
e7aa3f50
ZJS
78 { "help", no_argument, NULL, 'h' },
79 { "version", no_argument, NULL, ARG_VERSION },
80 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
81 { "all", no_argument, NULL, 'a' },
82 { "full", no_argument, NULL, 'l' },
83 { "machine", required_argument, NULL, 'M' },
256c1eba
ZJS
84 { "unit", optional_argument, NULL, 'u' },
85 { "user-unit", optional_argument, NULL, ARG_USER_UNIT },
eb9da376 86 {}
fa776d8e
LP
87 };
88
89 int c;
90
91 assert(argc >= 1);
92 assert(argv);
93
256c1eba 94 while ((c = getopt_long(argc, argv, "-hkalM:u::", options, NULL)) >= 0)
fa776d8e
LP
95
96 switch (c) {
97
98 case 'h':
37ec0fdd 99 return help();
fa776d8e 100
c3175a7f 101 case ARG_VERSION:
3f6fd1ba 102 return version();
c3175a7f 103
1968a360 104 case ARG_NO_PAGER:
0221d68a 105 arg_pager_flags |= PAGER_DISABLE;
1968a360
LP
106 break;
107
c3175a7f
LP
108 case 'a':
109 arg_all = true;
110 break;
111
d9855d87 112 case 'u':
e7aa3f50 113 arg_show_unit = SHOW_UNIT_SYSTEM;
256c1eba
ZJS
114 if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
115 return log_oom();
e7aa3f50
ZJS
116 break;
117
118 case ARG_USER_UNIT:
119 arg_show_unit = SHOW_UNIT_USER;
256c1eba
ZJS
120 if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
121 return log_oom();
122 break;
123
124 case 1:
125 /* positional argument */
126 if (strv_push(&arg_names, optarg) < 0)
127 return log_oom();
d9855d87
ZJS
128 break;
129
98a6e132 130 case 'l':
9bdbc2e2
LN
131 arg_full = true;
132 break;
133
1e5678d0
LP
134 case 'k':
135 arg_kernel_threads = true;
136 break;
137
38158b92
ZJS
138 case 'M':
139 arg_machine = optarg;
140 break;
141
fa776d8e
LP
142 case '?':
143 return -EINVAL;
144
145 default:
eb9da376 146 assert_not_reached("Unhandled option");
fa776d8e 147 }
fa776d8e 148
baaa35ad
ZJS
149 if (arg_machine && arg_show_unit != SHOW_UNIT_NONE)
150 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
151 "Cannot combine --unit or --user-unit with --machine=.");
d9855d87 152
fa776d8e
LP
153 return 1;
154}
155
58033c91 156static void show_cg_info(const char *controller, const char *path) {
a6a4d3c4 157
b4cccbc1 158 if (cg_all_unified() == 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER))
58033c91 159 printf("Controller %s; ", controller);
a6a4d3c4 160
945403e6 161 printf("Control group %s:\n", empty_to_root(path));
58033c91
EV
162 fflush(stdout);
163}
164
88325bf6 165static int run(int argc, char *argv[]) {
e049fa16 166 int r, output_flags;
fa776d8e
LP
167
168 log_parse_environment();
2396fb04 169 log_open();
fa776d8e 170
1e5678d0 171 r = parse_argv(argc, argv);
e049fa16 172 if (r <= 0)
88325bf6 173 return r;
fa776d8e 174
0221d68a 175 r = pager_open(arg_pager_flags);
ee5324aa
YW
176 if (r > 0 && arg_full < 0)
177 arg_full = true;
9bdbc2e2
LN
178
179 output_flags =
180 arg_all * OUTPUT_SHOW_ALL |
0ff308c8
LP
181 (arg_full > 0) * OUTPUT_FULL_WIDTH |
182 arg_kernel_threads * OUTPUT_KERNEL_THREADS;
1968a360 183
256c1eba 184 if (arg_names) {
d9855d87 185 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
e049fa16 186 _cleanup_free_ char *root = NULL;
256c1eba 187 char **name;
fa776d8e 188
256c1eba 189 STRV_FOREACH(name, arg_names) {
fa776d8e 190 int q;
baa89da4 191
e7aa3f50 192 if (arg_show_unit != SHOW_UNIT_NONE) {
d9855d87
ZJS
193 /* Command line arguments are unit names */
194 _cleanup_free_ char *cgroup = NULL;
195
196 if (!bus) {
197 /* Connect to the bus only if necessary */
e7aa3f50
ZJS
198 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL,
199 arg_show_unit == SHOW_UNIT_USER,
200 &bus);
88325bf6
YW
201 if (r < 0)
202 return log_error_errno(r, "Failed to create bus connection: %m");
d9855d87
ZJS
203 }
204
256c1eba 205 q = show_cgroup_get_unit_path_and_warn(bus, *name, &cgroup);
d9855d87
ZJS
206 if (q < 0)
207 goto failed;
208
209 if (isempty(cgroup)) {
256c1eba 210 log_warning("Unit %s not found.", *name);
d9855d87
ZJS
211 q = -ENOENT;
212 goto failed;
213 }
214
256c1eba 215 printf("Unit %s (%s):\n", *name, cgroup);
d9855d87
ZJS
216 fflush(stdout);
217
218 q = show_cgroup_by_path(cgroup, NULL, 0, output_flags);
219
256c1eba 220 } else if (path_startswith(*name, "/sys/fs/cgroup")) {
fa776d8e 221
256c1eba 222 printf("Directory %s:\n", *name);
e049fa16 223 fflush(stdout);
fa776d8e 224
256c1eba 225 q = show_cgroup_by_path(*name, NULL, 0, output_flags);
e049fa16
LP
226 } else {
227 _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
228 const char *controller, *path;
fa776d8e 229
d9855d87
ZJS
230 if (!root) {
231 /* Query root only if needed, treat error as fatal */
232 r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
233 if (r < 0)
88325bf6 234 return log_error_errno(r, "Failed to list cgroup tree: %m");
d9855d87
ZJS
235 }
236
65c88349
ZJS
237 q = cg_split_spec(*name, &c, &p);
238 if (q < 0) {
239 log_error_errno(q, "Failed to split argument %s: %m", *name);
d9855d87 240 goto failed;
13be4979
LN
241 }
242
e049fa16
LP
243 controller = c ?: SYSTEMD_CGROUP_CONTROLLER;
244 if (p) {
605405c6 245 j = strjoin(root, "/", p);
88325bf6
YW
246 if (!j)
247 return log_oom();
13be4979 248
858d36c1 249 path_simplify(j, false);
e049fa16
LP
250 path = j;
251 } else
252 path = root;
13be4979 253
58033c91 254 show_cg_info(controller, path);
13be4979 255
0ff308c8 256 q = show_cgroup(controller, path, NULL, 0, output_flags);
e049fa16 257 }
13be4979 258
d9855d87
ZJS
259 failed:
260 if (q < 0 && r >= 0)
e049fa16
LP
261 r = q;
262 }
263
264 } else {
265 bool done = false;
13be4979 266
e049fa16
LP
267 if (!arg_machine) {
268 _cleanup_free_ char *cwd = NULL;
269
d7249575 270 r = safe_getcwd(&cwd);
88325bf6
YW
271 if (r < 0)
272 return log_error_errno(r, "Cannot determine current working directory: %m");
1f16b4a6 273
e049fa16
LP
274 if (path_startswith(cwd, "/sys/fs/cgroup")) {
275 printf("Working directory %s:\n", cwd);
276 fflush(stdout);
277
0ff308c8 278 r = show_cgroup_by_path(cwd, NULL, 0, output_flags);
e049fa16
LP
279 done = true;
280 }
281 }
282
283 if (!done) {
284 _cleanup_free_ char *root = NULL;
285
d3e8277d 286 r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
e049fa16 287 if (r < 0)
88325bf6 288 return log_error_errno(r, "Failed to list cgroup tree: %m");
e049fa16 289
58033c91 290 show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
e049fa16 291
b1f044bb 292 printf("-.slice\n");
0ff308c8 293 r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags);
1f16b4a6 294 }
fa776d8e 295 }
e049fa16 296 if (r < 0)
88325bf6 297 return log_error_errno(r, "Failed to list cgroup tree: %m");
fa776d8e 298
88325bf6 299 return 0;
fa776d8e 300}
88325bf6
YW
301
302DEFINE_MAIN_FUNCTION(run);