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