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