]> git.proxmox.com Git - systemd.git/blame - src/cgls/cgls.c
New upstream version 236
[systemd.git] / src / cgls / cgls.c
CommitLineData
52ad194e 1/* SPDX-License-Identifier: LGPL-2.1+ */
663996b3
MS
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
663996b3
MS
21#include <errno.h>
22#include <getopt.h>
6300502b 23#include <stdio.h>
663996b3 24#include <string.h>
6300502b
MP
25#include <unistd.h>
26
27#include "sd-bus.h"
663996b3 28
db2df898 29#include "alloc-util.h"
6300502b 30#include "bus-util.h"
663996b3
MS
31#include "cgroup-show.h"
32#include "cgroup-util.h"
6300502b 33#include "fileio.h"
663996b3 34#include "log.h"
663996b3 35#include "output-mode.h"
6300502b
MP
36#include "pager.h"
37#include "path-util.h"
2897b343 38#include "strv.h"
60f067b4 39#include "unit-name.h"
6300502b 40#include "util.h"
663996b3
MS
41
42static bool arg_no_pager = false;
43static bool arg_kernel_threads = false;
44static bool arg_all = false;
2897b343
MP
45
46static enum {
47 SHOW_UNIT_NONE,
48 SHOW_UNIT_SYSTEM,
49 SHOW_UNIT_USER,
50} arg_show_unit = SHOW_UNIT_NONE;
51static char **arg_names = NULL;
52
663996b3
MS
53static int arg_full = -1;
54static char* arg_machine = NULL;
55
5eef597e 56static void help(void) {
663996b3
MS
57 printf("%s [OPTIONS...] [CGROUP...]\n\n"
58 "Recursively show control group contents.\n\n"
59 " -h --help Show this help\n"
60 " --version Show package version\n"
61 " --no-pager Do not pipe output into a pager\n"
62 " -a --all Show all groups, including empty\n"
2897b343
MP
63 " -u --unit Show the subtrees of specifified system units\n"
64 " --user-unit Show the subtrees of specifified user units\n"
14228c0d 65 " -l --full Do not ellipsize output\n"
663996b3 66 " -k Include kernel threads in output\n"
d9dfd233 67 " -M --machine= Show container\n"
5eef597e 68 , program_invocation_short_name);
663996b3
MS
69}
70
71static int parse_argv(int argc, char *argv[]) {
72
73 enum {
74 ARG_NO_PAGER = 0x100,
75 ARG_VERSION,
2897b343 76 ARG_USER_UNIT,
663996b3
MS
77 };
78
79 static const struct option options[] = {
2897b343
MP
80 { "help", no_argument, NULL, 'h' },
81 { "version", no_argument, NULL, ARG_VERSION },
82 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
83 { "all", no_argument, NULL, 'a' },
84 { "full", no_argument, NULL, 'l' },
85 { "machine", required_argument, NULL, 'M' },
86 { "unit", optional_argument, NULL, 'u' },
87 { "user-unit", optional_argument, NULL, ARG_USER_UNIT },
60f067b4 88 {}
663996b3
MS
89 };
90
91 int c;
92
93 assert(argc >= 1);
94 assert(argv);
95
2897b343 96 while ((c = getopt_long(argc, argv, "-hkalM:u::", options, NULL)) >= 0)
663996b3
MS
97
98 switch (c) {
99
100 case 'h':
5eef597e
MP
101 help();
102 return 0;
663996b3
MS
103
104 case ARG_VERSION:
6300502b 105 return version();
663996b3
MS
106
107 case ARG_NO_PAGER:
108 arg_no_pager = true;
109 break;
110
111 case 'a':
112 arg_all = true;
113 break;
114
2897b343
MP
115 case 'u':
116 arg_show_unit = SHOW_UNIT_SYSTEM;
117 if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
118 return log_oom();
119 break;
120
121 case ARG_USER_UNIT:
122 arg_show_unit = SHOW_UNIT_USER;
123 if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
124 return log_oom();
125 break;
126
127 case 1:
128 /* positional argument */
129 if (strv_push(&arg_names, optarg) < 0)
130 return log_oom();
131 break;
132
14228c0d 133 case 'l':
663996b3
MS
134 arg_full = true;
135 break;
136
137 case 'k':
138 arg_kernel_threads = true;
139 break;
140
141 case 'M':
142 arg_machine = optarg;
143 break;
144
145 case '?':
146 return -EINVAL;
147
148 default:
60f067b4 149 assert_not_reached("Unhandled option");
663996b3 150 }
663996b3 151
2897b343
MP
152 if (arg_machine && arg_show_unit != SHOW_UNIT_NONE) {
153 log_error("Cannot combine --unit or --user-unit with --machine=.");
154 return -EINVAL;
d9dfd233
MP
155 }
156
2897b343 157 return 1;
d9dfd233
MP
158}
159
6300502b 160static void show_cg_info(const char *controller, const char *path) {
db2df898 161
2897b343 162 if (cg_all_unified() == 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER))
6300502b 163 printf("Controller %s; ", controller);
db2df898 164
6300502b
MP
165 printf("Control group %s:\n", isempty(path) ? "/" : path);
166 fflush(stdout);
167}
168
d9dfd233
MP
169int main(int argc, char *argv[]) {
170 int r, output_flags;
663996b3
MS
171
172 log_parse_environment();
173 log_open();
174
175 r = parse_argv(argc, argv);
d9dfd233 176 if (r <= 0)
663996b3 177 goto finish;
663996b3
MS
178
179 if (!arg_no_pager) {
aa27b158 180 r = pager_open(arg_no_pager, false);
d9dfd233
MP
181 if (r > 0 && arg_full < 0)
182 arg_full = true;
663996b3
MS
183 }
184
185 output_flags =
186 arg_all * OUTPUT_SHOW_ALL |
aa27b158
MP
187 (arg_full > 0) * OUTPUT_FULL_WIDTH |
188 arg_kernel_threads * OUTPUT_KERNEL_THREADS;
663996b3 189
2897b343
MP
190 if (arg_names) {
191 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
d9dfd233 192 _cleanup_free_ char *root = NULL;
2897b343 193 char **name;
663996b3 194
2897b343 195 STRV_FOREACH(name, arg_names) {
663996b3 196 int q;
14228c0d 197
2897b343
MP
198 if (arg_show_unit != SHOW_UNIT_NONE) {
199 /* Command line arguments are unit names */
200 _cleanup_free_ char *cgroup = NULL;
201
202 if (!bus) {
203 /* Connect to the bus only if necessary */
204 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL,
205 arg_show_unit == SHOW_UNIT_USER,
206 &bus);
207 if (r < 0) {
208 log_error_errno(r, "Failed to create bus connection: %m");
209 goto finish;
210 }
211 }
212
213 q = show_cgroup_get_unit_path_and_warn(bus, *name, &cgroup);
214 if (q < 0)
215 goto failed;
216
217 if (isempty(cgroup)) {
218 log_warning("Unit %s not found.", *name);
219 q = -ENOENT;
220 goto failed;
221 }
222
223 printf("Unit %s (%s):\n", *name, cgroup);
224 fflush(stdout);
225
226 q = show_cgroup_by_path(cgroup, NULL, 0, output_flags);
663996b3 227
2897b343
MP
228 } else if (path_startswith(*name, "/sys/fs/cgroup")) {
229
230 printf("Directory %s:\n", *name);
d9dfd233
MP
231 fflush(stdout);
232
2897b343 233 q = show_cgroup_by_path(*name, NULL, 0, output_flags);
d9dfd233
MP
234 } else {
235 _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
236 const char *controller, *path;
237
2897b343
MP
238 if (!root) {
239 /* Query root only if needed, treat error as fatal */
240 r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
241 if (r < 0)
242 goto finish;
243 }
244
245 q = cg_split_spec(*name, &c, &p);
246 if (q < 0) {
247 log_error_errno(q, "Failed to split argument %s: %m", *name);
248 goto failed;
d9dfd233
MP
249 }
250
251 controller = c ?: SYSTEMD_CGROUP_CONTROLLER;
252 if (p) {
2897b343 253 j = strjoin(root, "/", p);
d9dfd233
MP
254 if (!j) {
255 r = log_oom();
256 goto finish;
257 }
258
259 path_kill_slashes(j);
260 path = j;
261 } else
262 path = root;
263
6300502b 264 show_cg_info(controller, path);
d9dfd233 265
aa27b158 266 q = show_cgroup(controller, path, NULL, 0, output_flags);
d9dfd233 267 }
663996b3 268
2897b343
MP
269 failed:
270 if (q < 0 && r >= 0)
663996b3
MS
271 r = q;
272 }
273
274 } else {
d9dfd233 275 bool done = false;
663996b3 276
d9dfd233
MP
277 if (!arg_machine) {
278 _cleanup_free_ char *cwd = NULL;
663996b3 279
d9dfd233
MP
280 cwd = get_current_dir_name();
281 if (!cwd) {
282 r = log_error_errno(errno, "Cannot determine current working directory: %m");
283 goto finish;
284 }
60f067b4 285
d9dfd233
MP
286 if (path_startswith(cwd, "/sys/fs/cgroup")) {
287 printf("Working directory %s:\n", cwd);
288 fflush(stdout);
60f067b4 289
aa27b158 290 r = show_cgroup_by_path(cwd, NULL, 0, output_flags);
d9dfd233
MP
291 done = true;
292 }
293 }
60f067b4 294
d9dfd233
MP
295 if (!done) {
296 _cleanup_free_ char *root = NULL;
60f067b4 297
2897b343 298 r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
d9dfd233 299 if (r < 0)
663996b3 300 goto finish;
663996b3 301
6300502b 302 show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
d9dfd233 303
db2df898 304 printf("-.slice\n");
aa27b158 305 r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags);
663996b3
MS
306 }
307 }
308
d9dfd233
MP
309 if (r < 0)
310 log_error_errno(r, "Failed to list cgroup tree: %m");
663996b3
MS
311
312finish:
313 pager_close();
2897b343 314 free(arg_names); /* don't free the strings */
663996b3 315
d9dfd233 316 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
663996b3 317}