chiark / gitweb /
util: add is_main_thread() call
[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) {
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 (n >= n_allocated) {
86                         pid_t *npids;
87
88                         n_allocated = MAX(16U, n*2U);
89
90                         if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
91                                 r = -ENOMEM;
92                                 goto finish;
93                         }
94
95                         pids = npids;
96                 }
97
98                 assert(n < n_allocated);
99                 pids[n++] = pid;
100
101                 if (pid > biggest)
102                         biggest = pid;
103         }
104
105         if (r < 0)
106                 goto finish;
107
108         if (n > 0) {
109                 unsigned i, m;
110
111                 /* Filter duplicates */
112                 m = 0;
113                 for (i = 0; i < n; i++) {
114                         unsigned j;
115
116                         for (j = i+1; j < n; j++)
117                                 if (pids[i] == pids[j])
118                                         break;
119
120                         if (j >= n)
121                                 pids[m++] = pids[i];
122                 }
123                 n = m;
124
125                 /* And sort */
126                 qsort(pids, n, sizeof(pid_t), compare);
127
128                 if (n_columns > 8)
129                         n_columns -= 8;
130                 else
131                         n_columns = 20;
132
133                 for (i = 0; i < n; i++) {
134                         char *t = NULL;
135
136                         get_process_cmdline(pids[i], n_columns, &t);
137
138                         printf("%s%s %*lu %s\n",
139                                prefix,
140                                (more || i < n-1) ? "\342\224\234" : "\342\224\224",
141                                (int) ilog10(biggest),
142                                (unsigned long) pids[i],
143                                strna(t));
144
145                         free(t);
146                 }
147         }
148
149         r = 0;
150
151 finish:
152         free(pids);
153
154         if (f)
155                 fclose(f);
156
157         return r;
158 }
159
160 int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns) {
161         DIR *d;
162         char *last = NULL;
163         char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
164         bool shown_pids = false;
165         int r;
166
167         if (n_columns <= 0)
168                 n_columns = columns();
169
170         if (!prefix)
171                 prefix = "";
172
173         if ((r = cg_fix_path(path, &fn)) < 0)
174                 return r;
175
176         if (!(d = opendir(fn))) {
177                 free(fn);
178                 return -errno;
179         }
180
181         while ((r = cg_read_subgroup(d, &gn)) > 0) {
182
183                 if (!shown_pids) {
184                         show_cgroup_one_by_path(path, prefix, n_columns, true);
185                         shown_pids = true;
186                 }
187
188                 if (last) {
189                         printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
190
191                         if (!p1)
192                                 if (!(p1 = strappend(prefix, "\342\224\202 "))) {
193                                         r = -ENOMEM;
194                                         goto finish;
195                                 }
196
197                         show_cgroup_by_path(last, p1, n_columns-2);
198
199                         free(last);
200                         last = NULL;
201                 }
202
203                 r = asprintf(&last, "%s/%s", fn, gn);
204                 free(gn);
205
206                 if (r < 0) {
207                         r = -ENOMEM;
208                         goto finish;
209                 }
210         }
211
212         if (r < 0)
213                 goto finish;
214
215         if (!shown_pids)
216                 show_cgroup_one_by_path(path, prefix, n_columns, !!last);
217
218         if (last) {
219                 printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
220
221                 if (!p2)
222                         if (!(p2 = strappend(prefix, "  "))) {
223                                 r = -ENOMEM;
224                                 goto finish;
225                         }
226
227                 show_cgroup_by_path(last, p2, n_columns-2);
228         }
229
230         r = 0;
231
232 finish:
233         free(p1);
234         free(p2);
235         free(last);
236         free(fn);
237
238         closedir(d);
239
240         return r;
241 }
242
243 int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns) {
244         char *p;
245         int r;
246
247         assert(controller);
248         assert(path);
249
250         if ((r = cg_get_path(controller, path, NULL, &p)) < 0)
251                 return r;
252
253         r = show_cgroup_by_path(p, prefix, n_columns);
254         free(p);
255
256         return r;
257 }