chiark / gitweb /
move more common files to shared/ and add them to shared.la
[elogind.git] / src / shared / 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 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 <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 }