]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cgls/cgls.c
core: unified cgroup hierarchy support
[thirdparty/systemd.git] / src / cgls / cgls.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <getopt.h>
26 #include <string.h>
27
28 #include "cgroup-show.h"
29 #include "cgroup-util.h"
30 #include "log.h"
31 #include "path-util.h"
32 #include "util.h"
33 #include "pager.h"
34 #include "build.h"
35 #include "output-mode.h"
36 #include "fileio.h"
37 #include "sd-bus.h"
38 #include "bus-util.h"
39 #include "bus-error.h"
40 #include "unit-name.h"
41
42 static bool arg_no_pager = false;
43 static bool arg_kernel_threads = false;
44 static bool arg_all = false;
45 static int arg_full = -1;
46 static char* arg_machine = NULL;
47
48 static void help(void) {
49 printf("%s [OPTIONS...] [CGROUP...]\n\n"
50 "Recursively show control group contents.\n\n"
51 " -h --help Show this help\n"
52 " --version Show package version\n"
53 " --no-pager Do not pipe output into a pager\n"
54 " -a --all Show all groups, including empty\n"
55 " -l --full Do not ellipsize output\n"
56 " -k Include kernel threads in output\n"
57 " -M --machine= Show container\n"
58 , program_invocation_short_name);
59 }
60
61 static int parse_argv(int argc, char *argv[]) {
62
63 enum {
64 ARG_NO_PAGER = 0x100,
65 ARG_VERSION,
66 };
67
68 static const struct option options[] = {
69 { "help", no_argument, NULL, 'h' },
70 { "version", no_argument, NULL, ARG_VERSION },
71 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
72 { "all", no_argument, NULL, 'a' },
73 { "full", no_argument, NULL, 'l' },
74 { "machine", required_argument, NULL, 'M' },
75 {}
76 };
77
78 int c;
79
80 assert(argc >= 1);
81 assert(argv);
82
83 while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0)
84
85 switch (c) {
86
87 case 'h':
88 help();
89 return 0;
90
91 case ARG_VERSION:
92 puts(PACKAGE_STRING);
93 puts(SYSTEMD_FEATURES);
94 return 0;
95
96 case ARG_NO_PAGER:
97 arg_no_pager = true;
98 break;
99
100 case 'a':
101 arg_all = true;
102 break;
103
104 case 'l':
105 arg_full = true;
106 break;
107
108 case 'k':
109 arg_kernel_threads = true;
110 break;
111
112 case 'M':
113 arg_machine = optarg;
114 break;
115
116 case '?':
117 return -EINVAL;
118
119 default:
120 assert_not_reached("Unhandled option");
121 }
122
123 return 1;
124 }
125
126 static int get_cgroup_root(char **ret) {
127 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
128 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
129 _cleanup_free_ char *unit = NULL, *path = NULL;
130 const char *m;
131 int r;
132
133 if (!arg_machine) {
134 r = cg_get_root_path(ret);
135 if (r < 0)
136 return log_error_errno(r, "Failed to get root control group path: %m");
137
138 return 0;
139 }
140
141 m = strjoina("/run/systemd/machines/", arg_machine);
142 r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
143 if (r < 0)
144 return log_error_errno(r, "Failed to load machine data: %m");
145
146 path = unit_dbus_path_from_name(unit);
147 if (!path)
148 return log_oom();
149
150 r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
151 if (r < 0)
152 return log_error_errno(r, "Failed to create bus connection: %m");
153
154 r = sd_bus_get_property_string(
155 bus,
156 "org.freedesktop.systemd1",
157 path,
158 unit_dbus_interface_from_name(unit),
159 "ControlGroup",
160 &error,
161 ret);
162 if (r < 0)
163 return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
164
165 return 0;
166 }
167
168 int main(int argc, char *argv[]) {
169 int r, output_flags;
170
171 log_parse_environment();
172 log_open();
173
174 r = parse_argv(argc, argv);
175 if (r <= 0)
176 goto finish;
177
178 if (!arg_no_pager) {
179 r = pager_open(false);
180 if (r > 0 && arg_full < 0)
181 arg_full = true;
182 }
183
184 output_flags =
185 arg_all * OUTPUT_SHOW_ALL |
186 (arg_full > 0) * OUTPUT_FULL_WIDTH;
187
188 if (optind < argc) {
189 _cleanup_free_ char *root = NULL;
190 int i;
191
192 r = get_cgroup_root(&root);
193 if (r < 0)
194 goto finish;
195
196 for (i = optind; i < argc; i++) {
197 int q;
198
199 if (path_startswith(argv[i], "/sys/fs/cgroup")) {
200
201 printf("Directory %s:\n", argv[i]);
202 fflush(stdout);
203
204 q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags);
205 } else {
206 _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
207 const char *controller, *path;
208
209 r = cg_split_spec(argv[i], &c, &p);
210 if (r < 0) {
211 log_error_errno(r, "Failed to split argument %s: %m", argv[i]);
212 goto finish;
213 }
214
215 controller = c ?: SYSTEMD_CGROUP_CONTROLLER;
216 if (p) {
217 j = strjoin(root, "/", p, NULL);
218 if (!j) {
219 r = log_oom();
220 goto finish;
221 }
222
223 path_kill_slashes(j);
224 path = j;
225 } else
226 path = root;
227
228 if (cg_unified() > 0)
229 printf("Control group %s:\n", path);
230 else
231 printf("Controller %s; control group %s:\n", controller, path);
232 fflush(stdout);
233
234 q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags);
235 }
236
237 if (q < 0)
238 r = q;
239 }
240
241 } else {
242 bool done = false;
243
244 if (!arg_machine) {
245 _cleanup_free_ char *cwd = NULL;
246
247 cwd = get_current_dir_name();
248 if (!cwd) {
249 r = log_error_errno(errno, "Cannot determine current working directory: %m");
250 goto finish;
251 }
252
253 if (path_startswith(cwd, "/sys/fs/cgroup")) {
254 printf("Working directory %s:\n", cwd);
255 fflush(stdout);
256
257 r = show_cgroup_by_path(cwd, NULL, 0, arg_kernel_threads, output_flags);
258 done = true;
259 }
260 }
261
262 if (!done) {
263 _cleanup_free_ char *root = NULL;
264
265 r = get_cgroup_root(&root);
266 if (r < 0)
267 goto finish;
268
269 printf("Control group %s:\n", isempty(root) ? "/" : root);
270 fflush(stdout);
271
272 r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
273 }
274 }
275
276 if (r < 0)
277 log_error_errno(r, "Failed to list cgroup tree: %m");
278
279 finish:
280 pager_close();
281
282 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
283 }