chiark / gitweb /
journald: copy metrics/compression state from template when rotating
[elogind.git] / src / cgroup-show.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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <dirent.h>
25 #include <errno.h>
26
27 #include "util.h"
28 #include "macro.h"
29 #include "cgroup-util.h"
30 #include "cgroup-show.h"
31
32 static int compare(const void *a, const void *b) {
33         const pid_t *p = a, *q = b;
34
35         if (*p < *q)
36                 return -1;
37         if (*p > *q)
38                 return 1;
39         return 0;
40 }
41
42 static unsigned ilog10(unsigned long ul) {
43         int n = 0;
44
45         while (ul > 0) {
46                 n++;
47                 ul /= 10;
48         }
49
50         return n;
51 }
52
53 static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) {
54         char *fn;
55         FILE *f;
56         size_t n = 0, n_allocated = 0;
57         pid_t *pids = NULL;
58         char *p;
59         pid_t pid, biggest = 0;
60         int r;
61
62         if (n_columns <= 0)
63                 n_columns = columns();
64
65         if (!prefix)
66                 prefix = "";
67
68         if ((r = cg_fix_path(path, &p)) < 0)
69                 return r;
70
71         r = asprintf(&fn, "%s/cgroup.procs", p);
72         free(p);
73
74         if (r < 0)
75                 return -ENOMEM;
76
77         f = fopen(fn, "re");
78         free(fn);
79
80         if (!f)
81                 return -errno;
82
83         while ((r = cg_read_pid(f, &pid)) > 0) {
84
85                 if (!kernel_threads && is_kernel_thread(pid) > 0)
86                         continue;
87
88                 if (n >= n_allocated) {
89                         pid_t *npids;
90
91                         n_allocated = MAX(16U, n*2U);
92
93                         if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
94                                 r = -ENOMEM;
95                                 goto finish;
96                         }
97
98                         pids = npids;
99                 }
100
101                 assert(n < n_allocated);
102                 pids[n++] = pid;
103
104                 if (pid > biggest)
105                         biggest = pid;
106         }
107
108         if (r < 0)
109                 goto finish;
110
111         if (n > 0) {
112                 unsigned i, m;
113
114                 /* Filter duplicates */
115                 m = 0;
116                 for (i = 0; i < n; i++) {
117                         unsigned j;
118
119                         for (j = i+1; j < n; j++)
120                                 if (pids[i] == pids[j])
121                                         break;
122
123                         if (j >= n)
124                                 pids[m++] = pids[i];
125                 }
126                 n = m;
127
128                 /* And sort */
129                 qsort(pids, n, sizeof(pid_t), compare);
130
131                 if (n_columns > 8)
132                         n_columns -= 8;
133                 else
134                         n_columns = 20;
135
136                 for (i = 0; i < n; i++) {
137                         char *t = NULL;
138
139                         get_process_cmdline(pids[i], n_columns, true, &t);
140
141                         printf("%s%s %*lu %s\n",
142                                prefix,
143                                (more || i < n-1) ? "\342\224\234" : "\342\224\224",
144                                (int) ilog10(biggest),
145                                (unsigned long) pids[i],
146                                strna(t));
147
148                         free(t);
149                 }
150         }
151
152         r = 0;
153
154 finish:
155         free(pids);
156
157         if (f)
158                 fclose(f);
159
160         return r;
161 }
162
163 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
164         DIR *d;
165         char *last = NULL;
166         char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
167         bool shown_pids = false;
168         int r;
169
170         if (n_columns <= 0)
171                 n_columns = columns();
172
173         if (!prefix)
174                 prefix = "";
175
176         if ((r = cg_fix_path(path, &fn)) < 0)
177                 return r;
178
179         if (!(d = opendir(fn))) {
180                 free(fn);
181                 return -errno;
182         }
183
184         while ((r = cg_read_subgroup(d, &gn)) > 0) {
185
186                 if (!shown_pids) {
187                         show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads);
188                         shown_pids = true;
189                 }
190
191                 if (last) {
192                         printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
193
194                         if (!p1)
195                                 if (!(p1 = strappend(prefix, "\342\224\202 "))) {
196                                         r = -ENOMEM;
197                                         goto finish;
198                                 }
199
200                         show_cgroup_by_path(last, p1, n_columns-2, kernel_threads);
201
202                         free(last);
203                         last = NULL;
204                 }
205
206                 r = asprintf(&last, "%s/%s", fn, gn);
207                 free(gn);
208
209                 if (r < 0) {
210                         r = -ENOMEM;
211                         goto finish;
212                 }
213         }
214
215         if (r < 0)
216                 goto finish;
217
218         if (!shown_pids)
219                 show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads);
220
221         if (last) {
222                 printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
223
224                 if (!p2)
225                         if (!(p2 = strappend(prefix, "  "))) {
226                                 r = -ENOMEM;
227                                 goto finish;
228                         }
229
230                 show_cgroup_by_path(last, p2, n_columns-2, kernel_threads);
231         }
232
233         r = 0;
234
235 finish:
236         free(p1);
237         free(p2);
238         free(last);
239         free(fn);
240
241         closedir(d);
242
243         return r;
244 }
245
246 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
247         char *p;
248         int r;
249
250         assert(controller);
251         assert(path);
252
253         r = cg_get_path(controller, path, NULL, &p);
254         if (r < 0)
255                 return r;
256
257         r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads);
258         free(p);
259
260         return r;
261 }