chiark / gitweb /
bec9b59260ffb73d0b34ddebc3ebee99b8036086
[elogind.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 <limits.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <getopt.h>
27 #include <string.h>
28
29 #include "cgroup-show.h"
30 #include "cgroup-util.h"
31 #include "log.h"
32 #include "path-util.h"
33 #include "util.h"
34 #include "pager.h"
35 #include "build.h"
36 #include "output-mode.h"
37 #include "fileio.h"
38 #include "sd-bus.h"
39 #include "bus-util.h"
40 #include "bus-error.h"
41 #include "unit-name.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 int help(void) {
50
51         printf("%s [OPTIONS...] [CGROUP...]\n\n"
52                "Recursively show control group contents.\n\n"
53                "  -h --help           Show this help\n"
54                "     --version        Show package version\n"
55                "     --no-pager       Do not pipe output into a pager\n"
56                "  -a --all            Show all groups, including empty\n"
57                "  -l --full           Do not ellipsize output\n"
58                "  -k                  Include kernel threads in output\n"
59                "  -M --machine        Show container\n",
60                program_invocation_short_name);
61
62         return 0;
63 }
64
65 static int parse_argv(int argc, char *argv[]) {
66
67         enum {
68                 ARG_NO_PAGER = 0x100,
69                 ARG_VERSION,
70         };
71
72         static const struct option options[] = {
73                 { "help",      no_argument,       NULL, 'h'          },
74                 { "version",   no_argument,       NULL, ARG_VERSION  },
75                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER },
76                 { "all",       no_argument,       NULL, 'a'          },
77                 { "full",      no_argument,       NULL, 'l'          },
78                 { "machine",   required_argument, NULL, 'M'          },
79                 {}
80         };
81
82         int c;
83
84         assert(argc >= 1);
85         assert(argv);
86
87         while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0) {
88
89                 switch (c) {
90
91                 case 'h':
92                         return help();
93
94                 case ARG_VERSION:
95                         puts(PACKAGE_STRING);
96                         puts(SYSTEMD_FEATURES);
97                         return 0;
98
99                 case ARG_NO_PAGER:
100                         arg_no_pager = true;
101                         break;
102
103                 case 'a':
104                         arg_all = true;
105                         break;
106
107                 case 'l':
108                         arg_full = true;
109                         break;
110
111                 case 'k':
112                         arg_kernel_threads = true;
113                         break;
114
115                 case 'M':
116                         arg_machine = optarg;
117                         break;
118
119                 case '?':
120                         return -EINVAL;
121
122                 default:
123                         assert_not_reached("Unhandled option");
124                 }
125         }
126
127         return 1;
128 }
129
130 int main(int argc, char *argv[]) {
131         int r = 0, retval = EXIT_FAILURE;
132         int output_flags;
133         char _cleanup_free_ *root = NULL;
134         _cleanup_bus_unref_ sd_bus *bus = NULL;
135
136         log_parse_environment();
137         log_open();
138
139         r = parse_argv(argc, argv);
140         if (r < 0)
141                 goto finish;
142         else if (r == 0) {
143                 retval = EXIT_SUCCESS;
144                 goto finish;
145         }
146
147         if (!arg_no_pager) {
148                 r = pager_open(false);
149                 if (r > 0) {
150                         if (arg_full == -1)
151                                 arg_full = true;
152                 }
153         }
154
155         output_flags =
156                 arg_all * OUTPUT_SHOW_ALL |
157                 (arg_full > 0) * OUTPUT_FULL_WIDTH;
158
159         r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
160         if (r < 0) {
161                 log_error("Failed to create bus connection: %s", strerror(-r));
162                 goto finish;
163         }
164
165         if (optind < argc) {
166                 int i;
167
168                 for (i = optind; i < argc; i++) {
169                         int q;
170
171                         fprintf(stdout, "%s:\n", argv[i]);
172                         fflush(stdout);
173
174                         if (arg_machine)
175                                 root = strjoin("machine/", arg_machine, "/", argv[i], NULL);
176                         else
177                                 root = strdup(argv[i]);
178                         if (!root)
179                                 return log_oom();
180
181                         q = show_cgroup_by_path(root, NULL, 0,
182                                                 arg_kernel_threads, output_flags);
183                         if (q < 0)
184                                 r = q;
185                 }
186
187         } else {
188                 _cleanup_free_ char *p;
189
190                 p = get_current_dir_name();
191                 if (!p) {
192                         log_error("Cannot determine current working directory: %m");
193                         goto finish;
194                 }
195
196                 if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) {
197                         printf("Working Directory %s:\n", p);
198                         r = show_cgroup_by_path(p, NULL, 0,
199                                                 arg_kernel_threads, output_flags);
200                 } else {
201                         if (arg_machine) {
202                                 char *m;
203                                 const char *cgroup;
204                                 _cleanup_free_ char *scope = NULL;
205                                 _cleanup_free_ char *path = NULL;
206                                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
207                                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
208
209                                 m = strappenda("/run/systemd/machines/", arg_machine);
210                                 r = parse_env_file(m, NEWLINE, "SCOPE", &scope, NULL);
211                                 if (r < 0) {
212                                         log_error("Failed to get machine path: %s", strerror(-r));
213                                         goto finish;
214                                 }
215
216                                 path = unit_dbus_path_from_name(scope);
217                                 if (!path) {
218                                         log_oom();
219                                         goto finish;
220                                 }
221
222                                 r = sd_bus_get_property(
223                                                 bus,
224                                                 "org.freedesktop.systemd1",
225                                                 path,
226                                                 "org.freedesktop.systemd1.Scope",
227                                                 "ControlGroup",
228                                                 &error,
229                                                 &reply,
230                                                 "s");
231
232                                 if (r < 0) {
233                                         log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
234                                         goto finish;
235                                 }
236
237                                 r = sd_bus_message_read(reply, "s", &cgroup);
238                                 if (r < 0) {
239                                         bus_log_parse_error(r);
240                                         goto finish;
241                                 }
242
243                                 root = strdup(cgroup);
244                                 if (!root) {
245                                         log_oom();
246                                         goto finish;
247                                 }
248
249                         } else
250                                 r = cg_get_root_path(&root);
251                         if (r < 0) {
252                                 log_error("Failed to get %s path: %s",
253                                           arg_machine ? "machine" : "root", strerror(-r));
254                                 goto finish;
255                         }
256
257                         r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0,
258                                         arg_kernel_threads, output_flags);
259                 }
260         }
261
262         if (r < 0) {
263                 log_error("Failed to list cgroup tree %s: %s", root, strerror(-r));
264                 retval = EXIT_FAILURE;
265         } else
266                 retval = EXIT_SUCCESS;
267
268 finish:
269         pager_close();
270
271         return retval;
272 }