]>
Commit | Line | Data |
---|---|---|
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 | 26 | static PagerFlags arg_pager_flags = 0; |
1e5678d0 | 27 | static bool arg_kernel_threads = false; |
c3175a7f | 28 | static bool arg_all = false; |
e7aa3f50 ZJS |
29 | |
30 | static enum { | |
31 | SHOW_UNIT_NONE, | |
32 | SHOW_UNIT_SYSTEM, | |
33 | SHOW_UNIT_USER, | |
34 | } arg_show_unit = SHOW_UNIT_NONE; | |
256c1eba | 35 | static char **arg_names = NULL; |
e7aa3f50 | 36 | |
9bdbc2e2 | 37 | static int arg_full = -1; |
2428944e | 38 | static const char* arg_machine = NULL; |
fa776d8e | 39 | |
88325bf6 YW |
40 | STATIC_DESTRUCTOR_REGISTER(arg_names, freep); /* don't free the strings */ |
41 | ||
37ec0fdd LP |
42 | static 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 | ||
69 | static 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 | 156 | static 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 | 165 | static 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 | |
302 | DEFINE_MAIN_FUNCTION(run); |