chiark / gitweb /
cgroup: simplify how instantiated units are mapped to cgroups
[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 void 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
59 static int parse_argv(int argc, char *argv[]) {
60
61         enum {
62                 ARG_NO_PAGER = 0x100,
63                 ARG_VERSION,
64         };
65
66         static const struct option options[] = {
67                 { "help",      no_argument,       NULL, 'h'          },
68                 { "version",   no_argument,       NULL, ARG_VERSION  },
69                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER },
70                 { "all",       no_argument,       NULL, 'a'          },
71                 { "full",      no_argument,       NULL, 'l'          },
72                 { "machine",   required_argument, NULL, 'M'          },
73                 { NULL,        0,                 NULL, 0            }
74         };
75
76         int c;
77
78         assert(argc >= 1);
79         assert(argv);
80
81         while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0) {
82
83                 switch (c) {
84
85                 case 'h':
86                         help();
87                         return 0;
88
89                 case ARG_VERSION:
90                         puts(PACKAGE_STRING);
91                         puts(SYSTEMD_FEATURES);
92                         return 0;
93
94                 case ARG_NO_PAGER:
95                         arg_no_pager = true;
96                         break;
97
98                 case 'a':
99                         arg_all = true;
100                         break;
101
102                 case 'l':
103                         arg_full = true;
104                         break;
105
106                 case 'k':
107                         arg_kernel_threads = true;
108                         break;
109
110                 case 'M':
111                         arg_machine = optarg;
112                         break;
113
114                 case '?':
115                         return -EINVAL;
116
117                 default:
118                         log_error("Unknown option code %c", c);
119                         return -EINVAL;
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                         printf("%s:\n", argv[i]);
160
161                         if (arg_machine)
162                                 root = strjoin("machine/", arg_machine, "/", argv[i], NULL);
163                         else
164                                 root = strdup(argv[i]);
165                         if (!root)
166                                 return log_oom();
167
168                         q = show_cgroup_by_path(root, NULL, 0,
169                                                 arg_kernel_threads, output_flags);
170                         if (q < 0)
171                                 r = q;
172                 }
173
174         } else {
175                 _cleanup_free_ char *p;
176
177                 p = get_current_dir_name();
178                 if (!p) {
179                         log_error("Cannot determine current working directory: %m");
180                         goto finish;
181                 }
182
183                 if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) {
184                         printf("Working Directory %s:\n", p);
185                         r = show_cgroup_by_path(p, NULL, 0,
186                                                 arg_kernel_threads, output_flags);
187                 } else {
188                         if (arg_machine) {
189                                 char *m;
190                                 m = strappenda("/run/systemd/machines/", arg_machine);
191                                 r = parse_env_file(m, NEWLINE, "CGROUP", &root, NULL);
192                         } else
193                                 r = cg_get_root_path(&root);
194                         if (r < 0) {
195                                 log_error("Failed to get %s path: %s",
196                                           arg_machine ? "machine" : "root", strerror(-r));
197                                 goto finish;
198                         }
199
200                         r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0,
201                                         arg_kernel_threads, output_flags);
202                 }
203         }
204
205         if (r < 0) {
206                 log_error("Failed to list cgroup tree %s: %s", root, strerror(-r));
207                 retval = EXIT_FAILURE;
208         } else
209                 retval = EXIT_SUCCESS;
210
211 finish:
212         pager_close();
213
214         return retval;
215 }