]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cgls/cgls.c
core: unified cgroup hierarchy support
[thirdparty/systemd.git] / src / cgls / cgls.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
fa776d8e
LP
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
5430f7f2
LP
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
fa776d8e
LP
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
5430f7f2 16 Lesser General Public License for more details.
fa776d8e 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
fa776d8e
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
fa776d8e
LP
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"
c6c18be3 29#include "cgroup-util.h"
fa776d8e 30#include "log.h"
9eb977db 31#include "path-util.h"
fa776d8e 32#include "util.h"
1968a360 33#include "pager.h"
c3175a7f 34#include "build.h"
9bdbc2e2 35#include "output-mode.h"
9444b1f2 36#include "fileio.h"
13be4979
LN
37#include "sd-bus.h"
38#include "bus-util.h"
39#include "bus-error.h"
40#include "unit-name.h"
1968a360
LP
41
42static bool arg_no_pager = false;
1e5678d0 43static bool arg_kernel_threads = false;
c3175a7f 44static bool arg_all = false;
9bdbc2e2 45static int arg_full = -1;
38158b92 46static char* arg_machine = NULL;
fa776d8e 47
601185b4 48static void help(void) {
fa776d8e
LP
49 printf("%s [OPTIONS...] [CGROUP...]\n\n"
50 "Recursively show control group contents.\n\n"
69fc152f 51 " -h --help Show this help\n"
c3175a7f 52 " --version Show package version\n"
1e5678d0 53 " --no-pager Do not pipe output into a pager\n"
c3175a7f 54 " -a --all Show all groups, including empty\n"
98a6e132 55 " -l --full Do not ellipsize output\n"
38158b92 56 " -k Include kernel threads in output\n"
e049fa16 57 " -M --machine= Show container\n"
601185b4 58 , program_invocation_short_name);
fa776d8e
LP
59}
60
61static int parse_argv(int argc, char *argv[]) {
62
1968a360 63 enum {
c3175a7f 64 ARG_NO_PAGER = 0x100,
9bdbc2e2 65 ARG_VERSION,
1968a360
LP
66 };
67
fa776d8e 68 static const struct option options[] = {
1968a360 69 { "help", no_argument, NULL, 'h' },
c3175a7f 70 { "version", no_argument, NULL, ARG_VERSION },
1968a360 71 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
c3175a7f 72 { "all", no_argument, NULL, 'a' },
98a6e132 73 { "full", no_argument, NULL, 'l' },
38158b92 74 { "machine", required_argument, NULL, 'M' },
eb9da376 75 {}
fa776d8e
LP
76 };
77
78 int c;
79
80 assert(argc >= 1);
81 assert(argv);
82
601185b4 83 while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0)
fa776d8e
LP
84
85 switch (c) {
86
87 case 'h':
601185b4
ZJS
88 help();
89 return 0;
fa776d8e 90
c3175a7f
LP
91 case ARG_VERSION:
92 puts(PACKAGE_STRING);
c3175a7f
LP
93 puts(SYSTEMD_FEATURES);
94 return 0;
95
1968a360
LP
96 case ARG_NO_PAGER:
97 arg_no_pager = true;
98 break;
99
c3175a7f
LP
100 case 'a':
101 arg_all = true;
102 break;
103
98a6e132 104 case 'l':
9bdbc2e2
LN
105 arg_full = true;
106 break;
107
1e5678d0
LP
108 case 'k':
109 arg_kernel_threads = true;
110 break;
111
38158b92
ZJS
112 case 'M':
113 arg_machine = optarg;
114 break;
115
fa776d8e
LP
116 case '?':
117 return -EINVAL;
118
119 default:
eb9da376 120 assert_not_reached("Unhandled option");
fa776d8e 121 }
fa776d8e
LP
122
123 return 1;
124}
125
e049fa16
LP
126static int get_cgroup_root(char **ret) {
127 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
03976f7b 128 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
e049fa16
LP
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)
cb88a0a4 163 return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
e049fa16
LP
164
165 return 0;
166}
167
168int main(int argc, char *argv[]) {
169 int r, output_flags;
fa776d8e
LP
170
171 log_parse_environment();
2396fb04 172 log_open();
fa776d8e 173
1e5678d0 174 r = parse_argv(argc, argv);
e049fa16 175 if (r <= 0)
fa776d8e 176 goto finish;
fa776d8e 177
9bdbc2e2 178 if (!arg_no_pager) {
1b12a7b5 179 r = pager_open(false);
e049fa16
LP
180 if (r > 0 && arg_full < 0)
181 arg_full = true;
9bdbc2e2
LN
182 }
183
184 output_flags =
185 arg_all * OUTPUT_SHOW_ALL |
186 (arg_full > 0) * OUTPUT_FULL_WIDTH;
1968a360 187
fa776d8e 188 if (optind < argc) {
e049fa16 189 _cleanup_free_ char *root = NULL;
38158b92 190 int i;
fa776d8e 191
e049fa16
LP
192 r = get_cgroup_root(&root);
193 if (r < 0)
194 goto finish;
195
38158b92 196 for (i = optind; i < argc; i++) {
fa776d8e 197 int q;
baa89da4 198
e049fa16 199 if (path_startswith(argv[i], "/sys/fs/cgroup")) {
fa776d8e 200
e049fa16
LP
201 printf("Directory %s:\n", argv[i]);
202 fflush(stdout);
fa776d8e 203
e049fa16
LP
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;
fa776d8e 208
e049fa16 209 r = cg_split_spec(argv[i], &c, &p);
13be4979 210 if (r < 0) {
e049fa16 211 log_error_errno(r, "Failed to split argument %s: %m", argv[i]);
13be4979
LN
212 goto finish;
213 }
214
e049fa16
LP
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 }
13be4979 222
e049fa16
LP
223 path_kill_slashes(j);
224 path = j;
225 } else
226 path = root;
13be4979 227
efdb0237
LP
228 if (cg_unified() > 0)
229 printf("Control group %s:\n", path);
230 else
231 printf("Controller %s; control group %s:\n", controller, path);
e049fa16 232 fflush(stdout);
13be4979 233
e049fa16
LP
234 q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags);
235 }
13be4979 236
e049fa16
LP
237 if (q < 0)
238 r = q;
239 }
240
241 } else {
242 bool done = false;
13be4979 243
e049fa16
LP
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");
7027ff61 250 goto finish;
b9a8e638 251 }
1f16b4a6 252
e049fa16
LP
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
324496eb 269 printf("Control group %s:\n", isempty(root) ? "/" : root);
e049fa16
LP
270 fflush(stdout);
271
272 r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
1f16b4a6 273 }
fa776d8e
LP
274 }
275
e049fa16
LP
276 if (r < 0)
277 log_error_errno(r, "Failed to list cgroup tree: %m");
fa776d8e
LP
278
279finish:
1968a360 280 pager_close();
fa776d8e 281
e049fa16 282 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
fa776d8e 283}