chiark / gitweb /
machinectl: fix success check when getting pty from within container
[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
39 static bool arg_no_pager = false;
40 static bool arg_kernel_threads = false;
41 static bool arg_all = false;
42 static int arg_full = -1;
43 static char* arg_machine = NULL;
44
45 static int help(void) {
46
47         printf("%s [OPTIONS...] [CGROUP...]\n\n"
48                "Recursively show control group contents.\n\n"
49                "  -h --help           Show this help\n"
50                "     --version        Show package version\n"
51                "     --no-pager       Do not pipe output into a pager\n"
52                "  -a --all            Show all groups, including empty\n"
53                "  -l --full           Do not ellipsize output\n"
54                "  -k                  Include kernel threads in output\n"
55                "  -M --machine        Show container\n",
56                program_invocation_short_name);
57
58         return 0;
59 }
60
61 static int parse_argv(int argc, char *argv[]) {
62
63         enum {
64                 ARG_NO_PAGER = 0x100,
65                 ARG_VERSION,
66         };
67
68         static const struct option options[] = {
69                 { "help",      no_argument,       NULL, 'h'          },
70                 { "version",   no_argument,       NULL, ARG_VERSION  },
71                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER },
72                 { "all",       no_argument,       NULL, 'a'          },
73                 { "full",      no_argument,       NULL, 'l'          },
74                 { "machine",   required_argument, NULL, 'M'          },
75                 {}
76         };
77
78         int c;
79
80         assert(argc >= 1);
81         assert(argv);
82
83         while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0) {
84
85                 switch (c) {
86
87                 case 'h':
88                         return help();
89
90                 case ARG_VERSION:
91                         puts(PACKAGE_STRING);
92                         puts(SYSTEMD_FEATURES);
93                         return 0;
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
123         return 1;
124 }
125
126 int main(int argc, char *argv[]) {
127         int r = 0, retval = EXIT_FAILURE;
128         int output_flags;
129         char _cleanup_free_ *root = NULL;
130
131         log_parse_environment();
132         log_open();
133
134         r = parse_argv(argc, argv);
135         if (r < 0)
136                 goto finish;
137         else if (r == 0) {
138                 retval = EXIT_SUCCESS;
139                 goto finish;
140         }
141
142         if (!arg_no_pager) {
143                 r = pager_open(false);
144                 if (r > 0) {
145                         if (arg_full == -1)
146                                 arg_full = true;
147                 }
148         }
149
150         output_flags =
151                 arg_all * OUTPUT_SHOW_ALL |
152                 (arg_full > 0) * OUTPUT_FULL_WIDTH;
153
154         if (optind < argc) {
155                 int i;
156
157                 for (i = optind; i < argc; i++) {
158                         int q;
159
160                         fprintf(stdout, "%s:\n", argv[i]);
161                         fflush(stdout);
162
163                         if (arg_machine)
164                                 root = strjoin("machine/", arg_machine, "/", argv[i], NULL);
165                         else
166                                 root = strdup(argv[i]);
167                         if (!root)
168                                 return log_oom();
169
170                         q = show_cgroup_by_path(root, NULL, 0,
171                                                 arg_kernel_threads, output_flags);
172                         if (q < 0)
173                                 r = q;
174                 }
175
176         } else {
177                 _cleanup_free_ char *p;
178
179                 p = get_current_dir_name();
180                 if (!p) {
181                         log_error("Cannot determine current working directory: %m");
182                         goto finish;
183                 }
184
185                 if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) {
186                         printf("Working Directory %s:\n", p);
187                         r = show_cgroup_by_path(p, NULL, 0,
188                                                 arg_kernel_threads, output_flags);
189                 } else {
190                         if (arg_machine) {
191                                 char *m;
192                                 m = strappenda("/run/systemd/machines/", arg_machine);
193                                 r = parse_env_file(m, NEWLINE, "CGROUP", &root, NULL);
194                         } else
195                                 r = cg_get_root_path(&root);
196                         if (r < 0) {
197                                 log_error("Failed to get %s path: %s",
198                                           arg_machine ? "machine" : "root", strerror(-r));
199                                 goto finish;
200                         }
201
202                         r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0,
203                                         arg_kernel_threads, output_flags);
204                 }
205         }
206
207         if (r < 0) {
208                 log_error("Failed to list cgroup tree %s: %s", root, strerror(-r));
209                 retval = EXIT_FAILURE;
210         } else
211                 retval = EXIT_SUCCESS;
212
213 finish:
214         pager_close();
215
216         return retval;
217 }