chiark / gitweb /
treewide: no need to negate errno for log_*_errno()
[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 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                         puts(PACKAGE_STRING);
94                         puts(SYSTEMD_FEATURES);
95                         return 0;
96
97                 case ARG_NO_PAGER:
98                         arg_no_pager = true;
99                         break;
100
101                 case 'a':
102                         arg_all = true;
103                         break;
104
105                 case 'l':
106                         arg_full = true;
107                         break;
108
109                 case 'k':
110                         arg_kernel_threads = true;
111                         break;
112
113                 case 'M':
114                         arg_machine = optarg;
115                         break;
116
117                 case '?':
118                         return -EINVAL;
119
120                 default:
121                         assert_not_reached("Unhandled option");
122                 }
123
124         return 1;
125 }
126
127 int main(int argc, char *argv[]) {
128         int r = 0, retval = EXIT_FAILURE;
129         int output_flags;
130         _cleanup_free_ char *root = NULL;
131         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
132
133         log_parse_environment();
134         log_open();
135
136         r = parse_argv(argc, argv);
137         if (r < 0)
138                 goto finish;
139         else if (r == 0) {
140                 retval = EXIT_SUCCESS;
141                 goto finish;
142         }
143
144         if (!arg_no_pager) {
145                 r = pager_open(false);
146                 if (r > 0) {
147                         if (arg_full == -1)
148                                 arg_full = true;
149                 }
150         }
151
152         output_flags =
153                 arg_all * OUTPUT_SHOW_ALL |
154                 (arg_full > 0) * OUTPUT_FULL_WIDTH;
155
156         r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
157         if (r < 0) {
158                 log_error_errno(r, "Failed to create bus connection: %m");
159                 goto finish;
160         }
161
162         if (optind < argc) {
163                 int i;
164
165                 for (i = optind; i < argc; i++) {
166                         int q;
167
168                         fprintf(stdout, "%s:\n", argv[i]);
169                         fflush(stdout);
170
171                         if (arg_machine)
172                                 root = strjoin("machine/", arg_machine, "/", argv[i], NULL);
173                         else
174                                 root = strdup(argv[i]);
175                         if (!root)
176                                 return log_oom();
177
178                         q = show_cgroup_by_path(root, NULL, 0,
179                                                 arg_kernel_threads, output_flags);
180                         if (q < 0)
181                                 r = q;
182                 }
183
184         } else {
185                 _cleanup_free_ char *p;
186
187                 p = get_current_dir_name();
188                 if (!p) {
189                         log_error("Cannot determine current working directory: %m");
190                         goto finish;
191                 }
192
193                 if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) {
194                         printf("Working Directory %s:\n", p);
195                         r = show_cgroup_by_path(p, NULL, 0,
196                                                 arg_kernel_threads, output_flags);
197                 } else {
198                         if (arg_machine) {
199                                 char *m;
200                                 const char *cgroup;
201                                 _cleanup_free_ char *scope = NULL;
202                                 _cleanup_free_ char *path = NULL;
203                                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
204                                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
205
206                                 m = strappenda("/run/systemd/machines/", arg_machine);
207                                 r = parse_env_file(m, NEWLINE, "SCOPE", &scope, NULL);
208                                 if (r < 0) {
209                                         log_error_errno(r, "Failed to get machine path: %m");
210                                         goto finish;
211                                 }
212
213                                 path = unit_dbus_path_from_name(scope);
214                                 if (!path) {
215                                         log_oom();
216                                         goto finish;
217                                 }
218
219                                 r = sd_bus_get_property(
220                                                 bus,
221                                                 "org.freedesktop.systemd1",
222                                                 path,
223                                                 "org.freedesktop.systemd1.Scope",
224                                                 "ControlGroup",
225                                                 &error,
226                                                 &reply,
227                                                 "s");
228
229                                 if (r < 0) {
230                                         log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
231                                         goto finish;
232                                 }
233
234                                 r = sd_bus_message_read(reply, "s", &cgroup);
235                                 if (r < 0) {
236                                         bus_log_parse_error(r);
237                                         goto finish;
238                                 }
239
240                                 root = strdup(cgroup);
241                                 if (!root) {
242                                         log_oom();
243                                         goto finish;
244                                 }
245
246                         } else
247                                 r = cg_get_root_path(&root);
248                         if (r < 0) {
249                                 log_error("Failed to get %s path: %s",
250                                           arg_machine ? "machine" : "root", strerror(-r));
251                                 goto finish;
252                         }
253
254                         r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0,
255                                         arg_kernel_threads, output_flags);
256                 }
257         }
258
259         if (r < 0) {
260                 log_error_errno(r, "Failed to list cgroup tree %s: %m", root);
261                 retval = EXIT_FAILURE;
262         } else
263                 retval = EXIT_SUCCESS;
264
265 finish:
266         pager_close();
267
268         return retval;
269 }