chiark / gitweb /
a05f9795be26b0e351273751c6c062d254860e42
[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
38 static bool arg_no_pager = false;
39 static bool arg_kernel_threads = false;
40 static bool arg_all = false;
41 static int arg_full = -1;
42
43 static void help(void) {
44
45         printf("%s [OPTIONS...] [CGROUP...]\n\n"
46                "Recursively show control group contents.\n\n"
47                "  -h --help           Show this help\n"
48                "     --version        Show package version\n"
49                "     --no-pager       Do not pipe output into a pager\n"
50                "  -a --all            Show all groups, including empty\n"
51                "  --full              Do not ellipsize output\n"
52                "  -k                  Include kernel threads in output\n",
53                program_invocation_short_name);
54 }
55
56 static int parse_argv(int argc, char *argv[]) {
57
58         enum {
59                 ARG_NO_PAGER = 0x100,
60                 ARG_VERSION,
61                 ARG_FULL,
62         };
63
64         static const struct option options[] = {
65                 { "help",      no_argument,       NULL, 'h'          },
66                 { "version",   no_argument,       NULL, ARG_VERSION  },
67                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER },
68                 { "all",       no_argument,       NULL, 'a'          },
69                 { "full",      no_argument,       NULL, ARG_FULL     },
70                 { NULL,        0,                 NULL, 0            }
71         };
72
73         int c;
74
75         assert(argc >= 1);
76         assert(argv);
77
78         while ((c = getopt_long(argc, argv, "hka", options, NULL)) >= 0) {
79
80                 switch (c) {
81
82                 case 'h':
83                         help();
84                         return 0;
85
86                 case ARG_VERSION:
87                         puts(PACKAGE_STRING);
88                         puts(SYSTEMD_FEATURES);
89                         return 0;
90
91                 case ARG_NO_PAGER:
92                         arg_no_pager = true;
93                         break;
94
95                 case 'a':
96                         arg_all = true;
97                         break;
98
99                 case ARG_FULL:
100                         arg_full = true;
101                         break;
102
103                 case 'k':
104                         arg_kernel_threads = true;
105                         break;
106
107                 case '?':
108                         return -EINVAL;
109
110                 default:
111                         log_error("Unknown option code %c", c);
112                         return -EINVAL;
113                 }
114         }
115
116         return 1;
117 }
118
119 int main(int argc, char *argv[]) {
120         int r = 0, retval = EXIT_FAILURE;
121         int output_flags;
122
123         log_parse_environment();
124         log_open();
125
126         r = parse_argv(argc, argv);
127         if (r < 0)
128                 goto finish;
129         else if (r == 0) {
130                 retval = EXIT_SUCCESS;
131                 goto finish;
132         }
133
134         if (!arg_no_pager) {
135                 r = pager_open();
136                 if (r > 0) {
137                         if (arg_full == -1)
138                                 arg_full = true;
139                 }
140         }
141
142         output_flags =
143                 arg_all * OUTPUT_SHOW_ALL |
144                 (arg_full > 0) * OUTPUT_FULL_WIDTH;
145
146         if (optind < argc) {
147                 unsigned i;
148
149                 for (i = (unsigned) optind; i < (unsigned) argc; i++) {
150                         int q;
151                         printf("%s:\n", argv[i]);
152
153                         q = show_cgroup_by_path(argv[i], NULL, 0,
154                                                 arg_kernel_threads, output_flags);
155                         if (q < 0)
156                                 r = q;
157                 }
158
159         } else {
160                 char _cleanup_free_ *p;
161
162                 p = get_current_dir_name();
163                 if (!p) {
164                         log_error("Cannot determine current working directory: %m");
165                         goto finish;
166                 }
167
168                 if (path_startswith(p, "/sys/fs/cgroup")) {
169                         printf("Working Directory %s:\n", p);
170                         r = show_cgroup_by_path(p, NULL, 0,
171                                                 arg_kernel_threads, output_flags);
172                 } else {
173                         char _cleanup_free_ *root = NULL;
174                         const char *t = NULL;
175
176                         r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root);
177                         if (r < 0)
178                                 t = "/";
179                         else {
180                                 if (endswith(root, "/system"))
181                                         root[strlen(root)-7] = 0;
182
183                                 t = root[0] ? root : "/";
184                         }
185
186                         r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0,
187                                         arg_kernel_threads, output_flags);
188                 }
189         }
190
191         if (r < 0)
192                 log_error("Failed to list cgroup tree: %s", strerror(-r));
193
194         retval = EXIT_SUCCESS;
195
196 finish:
197         pager_close();
198
199         return retval;
200 }