]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cgls/cgls.c
tree-wide: drop NULL sentinel from strjoin
[thirdparty/systemd.git] / src / cgls / cgls.c
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
41 static bool arg_no_pager = false;
42 static bool arg_kernel_threads = false;
43 static bool arg_all = false;
44 static int arg_full = -1;
45 static char* arg_machine = NULL;
46
47 static 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
60 static 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
123 static 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
167 static void show_cg_info(const char *controller, const char *path) {
168
169 if (cg_all_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(arg_no_pager, 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 arg_kernel_threads * OUTPUT_KERNEL_THREADS;
196
197 if (optind < argc) {
198 _cleanup_free_ char *root = NULL;
199 int i;
200
201 r = get_cgroup_root(&root);
202 if (r < 0)
203 goto finish;
204
205 for (i = optind; i < argc; i++) {
206 int q;
207
208 if (path_startswith(argv[i], "/sys/fs/cgroup")) {
209
210 printf("Directory %s:\n", argv[i]);
211 fflush(stdout);
212
213 q = show_cgroup_by_path(argv[i], NULL, 0, output_flags);
214 } else {
215 _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
216 const char *controller, *path;
217
218 r = cg_split_spec(argv[i], &c, &p);
219 if (r < 0) {
220 log_error_errno(r, "Failed to split argument %s: %m", argv[i]);
221 goto finish;
222 }
223
224 controller = c ?: SYSTEMD_CGROUP_CONTROLLER;
225 if (p) {
226 j = strjoin(root, "/", p);
227 if (!j) {
228 r = log_oom();
229 goto finish;
230 }
231
232 path_kill_slashes(j);
233 path = j;
234 } else
235 path = root;
236
237 show_cg_info(controller, path);
238
239 q = show_cgroup(controller, path, NULL, 0, output_flags);
240 }
241
242 if (q < 0)
243 r = q;
244 }
245
246 } else {
247 bool done = false;
248
249 if (!arg_machine) {
250 _cleanup_free_ char *cwd = NULL;
251
252 cwd = get_current_dir_name();
253 if (!cwd) {
254 r = log_error_errno(errno, "Cannot determine current working directory: %m");
255 goto finish;
256 }
257
258 if (path_startswith(cwd, "/sys/fs/cgroup")) {
259 printf("Working directory %s:\n", cwd);
260 fflush(stdout);
261
262 r = show_cgroup_by_path(cwd, NULL, 0, output_flags);
263 done = true;
264 }
265 }
266
267 if (!done) {
268 _cleanup_free_ char *root = NULL;
269
270 r = get_cgroup_root(&root);
271 if (r < 0)
272 goto finish;
273
274 show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
275
276 printf("-.slice\n");
277 r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags);
278 }
279 }
280
281 if (r < 0)
282 log_error_errno(r, "Failed to list cgroup tree: %m");
283
284 finish:
285 pager_close();
286
287 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
288 }