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