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