]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cgls/cgls.c
Merge pull request #1983 from dmedri/master
[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 <errno.h>
23 #include <getopt.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "sd-bus.h"
29
30 #include "alloc-util.h"
31 #include "bus-error.h"
32 #include "bus-util.h"
33 #include "cgroup-show.h"
34 #include "cgroup-util.h"
35 #include "fileio.h"
36 #include "log.h"
37 #include "output-mode.h"
38 #include "pager.h"
39 #include "path-util.h"
40 #include "unit-name.h"
41 #include "util.h"
42
43 static bool arg_no_pager = false;
44 static bool arg_kernel_threads = false;
45 static bool arg_all = false;
46 static int arg_full = -1;
47 static char* arg_machine = NULL;
48
49 static void help(void) {
50 printf("%s [OPTIONS...] [CGROUP...]\n\n"
51 "Recursively show control group contents.\n\n"
52 " -h --help Show this help\n"
53 " --version Show package version\n"
54 " --no-pager Do not pipe output into a pager\n"
55 " -a --all Show all groups, including empty\n"
56 " -l --full Do not ellipsize output\n"
57 " -k Include kernel threads in output\n"
58 " -M --machine= Show container\n"
59 , program_invocation_short_name);
60 }
61
62 static int parse_argv(int argc, char *argv[]) {
63
64 enum {
65 ARG_NO_PAGER = 0x100,
66 ARG_VERSION,
67 };
68
69 static const struct option options[] = {
70 { "help", no_argument, NULL, 'h' },
71 { "version", no_argument, NULL, ARG_VERSION },
72 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
73 { "all", no_argument, NULL, 'a' },
74 { "full", no_argument, NULL, 'l' },
75 { "machine", required_argument, NULL, 'M' },
76 {}
77 };
78
79 int c;
80
81 assert(argc >= 1);
82 assert(argv);
83
84 while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0)
85
86 switch (c) {
87
88 case 'h':
89 help();
90 return 0;
91
92 case ARG_VERSION:
93 return version();
94
95 case ARG_NO_PAGER:
96 arg_no_pager = true;
97 break;
98
99 case 'a':
100 arg_all = true;
101 break;
102
103 case 'l':
104 arg_full = true;
105 break;
106
107 case 'k':
108 arg_kernel_threads = true;
109 break;
110
111 case 'M':
112 arg_machine = optarg;
113 break;
114
115 case '?':
116 return -EINVAL;
117
118 default:
119 assert_not_reached("Unhandled option");
120 }
121
122 return 1;
123 }
124
125 static int get_cgroup_root(char **ret) {
126 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
127 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
128 _cleanup_free_ char *unit = NULL, *path = NULL;
129 const char *m;
130 int r;
131
132 if (!arg_machine) {
133 r = cg_get_root_path(ret);
134 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
167 static 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
176 int 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
283 finish:
284 pager_close();
285
286 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
287 }