]> git.proxmox.com Git - mirror_lxcfs.git/blob - cgmanager.c
Release LXCFS 0.1
[mirror_lxcfs.git] / cgmanager.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 * (C) Copyright Canonical, Inc, 2014
6 *
7 * Authors:
8 * Daniel Lezcano <daniel.lezcano at free.fr>
9 * Serge Hallyn <serge.hallyn@ubuntu.com>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <dirent.h>
33 #include <fcntl.h>
34 #include <ctype.h>
35 #include <pthread.h>
36 #include <grp.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/param.h>
40 #include <sys/inotify.h>
41 #include <sys/mount.h>
42 #include <sys/wait.h>
43 #include <netinet/in.h>
44 #include <net/if.h>
45 #include <stdbool.h>
46
47 #include <nih-dbus/dbus_connection.h>
48 #include <cgmanager/cgmanager-client.h>
49 #include <nih/alloc.h>
50 #include <nih/error.h>
51 #include <nih/string.h>
52
53 #include "cgmanager.h"
54
55 static NihDBusProxy *cgroup_manager = NULL;
56 static int32_t api_version;
57
58 static void cgm_dbus_disconnect(void)
59 {
60 if (cgroup_manager) {
61 dbus_connection_flush(cgroup_manager->connection);
62 dbus_connection_close(cgroup_manager->connection);
63 nih_free(cgroup_manager);
64 }
65 cgroup_manager = NULL;
66 }
67
68 #define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
69 static bool cgm_dbus_connect(void)
70 {
71 DBusError dbus_error;
72 static DBusConnection *connection;
73
74 dbus_error_init(&dbus_error);
75
76 connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error);
77 if (!connection) {
78 fprintf(stderr, "Failed opening dbus connection: %s: %s\n",
79 dbus_error.name, dbus_error.message);
80 dbus_error_free(&dbus_error);
81 return false;
82 }
83 dbus_connection_set_exit_on_disconnect(connection, FALSE);
84 dbus_error_free(&dbus_error);
85 cgroup_manager = nih_dbus_proxy_new(NULL, connection,
86 NULL /* p2p */,
87 "/org/linuxcontainers/cgmanager", NULL, NULL);
88 dbus_connection_unref(connection);
89 if (!cgroup_manager) {
90 NihError *nerr;
91 nerr = nih_error_get();
92 fprintf(stderr, "Error opening cgmanager proxy: %s\n", nerr->message);
93 nih_free(nerr);
94 cgm_dbus_disconnect();
95 return false;
96 }
97
98 // get the api version
99 if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) {
100 NihError *nerr;
101 nerr = nih_error_get();
102 fprintf(stderr, "Error cgroup manager api version: %s\n", nerr->message);
103 nih_free(nerr);
104 cgm_dbus_disconnect();
105 return false;
106 }
107 return true;
108 }
109
110 bool cgm_get_controllers(char ***contrls)
111 {
112 if (!cgm_dbus_connect()) {
113 return false;
114 }
115
116 if ( cgmanager_list_controllers_sync(NULL, cgroup_manager, contrls) != 0 ) {
117 NihError *nerr;
118 nerr = nih_error_get();
119 fprintf(stderr, "call to list_controllers failed: %s\n", nerr->message);
120 nih_free(nerr);
121 cgm_dbus_disconnect();
122 return false;
123 }
124
125 cgm_dbus_disconnect();
126 return true;
127 }
128
129 bool cgm_list_keys(const char *controller, const char *cgroup, struct cgm_keys ***keys)
130 {
131 if (!cgm_dbus_connect()) {
132 return false;
133 }
134
135 if ( cgmanager_list_keys_sync(NULL, cgroup_manager, controller, cgroup,
136 (CgmanagerListKeysOutputElement ***)keys) != 0 ) {
137 NihError *nerr;
138 nerr = nih_error_get();
139 fprintf(stderr, "call to list_keys (%s:%s) failed: %s\n", controller, cgroup, nerr->message);
140 nih_free(nerr);
141 cgm_dbus_disconnect();
142 return false;
143 }
144
145 cgm_dbus_disconnect();
146 return true;
147 }
148
149 bool cgm_list_children(const char *controller, const char *cgroup, char ***list)
150 {
151 if (!cgm_dbus_connect()) {
152 return false;
153 }
154
155 if ( cgmanager_list_children_sync(NULL, cgroup_manager, controller, cgroup, list) != 0 ) {
156 NihError *nerr;
157 nerr = nih_error_get();
158 fprintf(stderr, "call to list_children (%s:%s) failed: %s\n", controller, cgroup, nerr->message);
159 nih_free(nerr);
160 cgm_dbus_disconnect();
161 return false;
162 }
163
164 cgm_dbus_disconnect();
165 return true;
166 }
167
168 char *cgm_get_pid_cgroup(pid_t pid, const char *controller)
169 {
170 char *output = NULL;
171
172 if (!cgm_dbus_connect()) {
173 return NULL;
174 }
175
176 if ( cgmanager_get_pid_cgroup_sync(NULL, cgroup_manager, controller, pid, &output) != 0 ) {
177 NihError *nerr;
178 nerr = nih_error_get();
179 fprintf(stderr, "call to get_pid_cgroup (%s) failed: %s\n", controller, nerr->message);
180 nih_free(nerr);
181 cgm_dbus_disconnect();
182 return NULL;
183 }
184
185 cgm_dbus_disconnect();
186 return output;
187 }
188
189 bool cgm_escape_cgroup(void)
190 {
191 if (!cgm_dbus_connect()) {
192 return false;
193 }
194
195 if ( cgmanager_move_pid_abs_sync(NULL, cgroup_manager, "all", "/", (int32_t) getpid()) != 0 ) {
196 NihError *nerr;
197 nerr = nih_error_get();
198 fprintf(stderr, "call to move_pid_abs (all:/) failed: %s\n", nerr->message);
199 nih_free(nerr);
200 cgm_dbus_disconnect();
201 return false;
202 }
203
204 cgm_dbus_disconnect();
205 return true;
206 }
207
208 bool cgm_move_pid(const char *controller, const char *cgroup, pid_t pid)
209 {
210 if (!cgm_dbus_connect()) {
211 return false;
212 }
213
214 if ( cgmanager_move_pid_sync(NULL, cgroup_manager, controller, cgroup,
215 (int32_t) pid) != 0 ) {
216 NihError *nerr;
217 nerr = nih_error_get();
218 fprintf(stderr, "call to move_pid (%s:%s, %d) failed: %s\n", controller, cgroup, pid, nerr->message);
219 nih_free(nerr);
220 cgm_dbus_disconnect();
221 return false;
222 }
223
224 cgm_dbus_disconnect();
225 return true;
226 }
227
228 bool cgm_get_value(const char *controller, const char *cgroup, const char *file,
229 char **value)
230 {
231 if (!cgm_dbus_connect()) {
232 return false;
233 }
234
235 if ( cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup,
236 file, value) != 0 ) {
237 NihError *nerr;
238 nerr = nih_error_get();
239 fprintf(stderr, "call to get_value (%s:%s, %s) failed: %s\n", controller, cgroup, file, nerr->message);
240 nih_free(nerr);
241 cgm_dbus_disconnect();
242 return false;
243 }
244
245 cgm_dbus_disconnect();
246 return true;
247 }
248
249 bool cgm_set_value(const char *controller, const char *cgroup, const char *file,
250 const char *value)
251 {
252 if (!cgm_dbus_connect()) {
253 return false;
254 }
255
256 if ( cgmanager_set_value_sync(NULL, cgroup_manager, controller, cgroup,
257 file, value) != 0 ) {
258 NihError *nerr;
259 nerr = nih_error_get();
260 fprintf(stderr, "call to set_value (%s:%s, %s, %s) failed: %s\n", controller, cgroup, file, value, nerr->message);
261 nih_free(nerr);
262 cgm_dbus_disconnect();
263 return false;
264 }
265
266 cgm_dbus_disconnect();
267 return true;
268 }
269
270 static int wait_for_pid(pid_t pid)
271 {
272 int status, ret;
273
274 again:
275 ret = waitpid(pid, &status, 0);
276 if (ret == -1) {
277 if (errno == EINTR)
278 goto again;
279 return -1;
280 }
281 if (ret != pid)
282 goto again;
283 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
284 return -1;
285 return 0;
286 }
287
288 bool cgm_create(const char *controller, const char *cg, uid_t uid, gid_t gid)
289 {
290 int32_t e;
291 pid_t pid = fork();
292
293 if (pid) {
294 if (wait_for_pid(pid) != 0)
295 return false;
296 return true;
297 }
298
299 if (setgroups(0, NULL))
300 exit(1);
301 if (setresgid(gid, gid, gid))
302 exit(1);
303 if (setresuid(uid, uid, uid))
304 exit(1);
305
306 if (!cgm_dbus_connect()) {
307 exit(1);
308 }
309
310 if ( cgmanager_create_sync(NULL, cgroup_manager, controller, cg, &e) != 0) {
311 NihError *nerr;
312 nerr = nih_error_get();
313 fprintf(stderr, "call to create failed (%s:%s): %s\n", controller, cg, nerr->message);
314 nih_free(nerr);
315 cgm_dbus_disconnect();
316 exit(1);
317 }
318
319 cgm_dbus_disconnect();
320 exit(0);
321 }
322
323 bool cgm_chown_file(const char *controller, const char *cg, uid_t uid, gid_t gid)
324 {
325 if (!cgm_dbus_connect()) {
326 return false;
327 }
328
329 if ( cgmanager_chown_sync(NULL, cgroup_manager, controller, cg, uid, gid) != 0) {
330 NihError *nerr;
331 nerr = nih_error_get();
332 fprintf(stderr, "call to chown (%s:%s, %d, %d) failed: %s\n", controller, cg, uid, gid, nerr->message);
333 nih_free(nerr);
334 cgm_dbus_disconnect();
335 return false;
336 }
337
338 cgm_dbus_disconnect();
339 return true;
340 }
341
342 bool cgm_chmod_file(const char *controller, const char *file, mode_t mode)
343 {
344 if (!cgm_dbus_connect()) {
345 return false;
346 }
347
348 if ( cgmanager_chmod_sync(NULL, cgroup_manager, controller, file, "", mode) != 0) {
349 NihError *nerr;
350 nerr = nih_error_get();
351 fprintf(stderr, "call to chmod (%s:%s, %d) failed: %s\n", controller, file, mode, nerr->message);
352 nih_free(nerr);
353 cgm_dbus_disconnect();
354 return false;
355 }
356
357 cgm_dbus_disconnect();
358 return true;
359 }
360
361 bool cgm_remove(const char *controller, const char *cg)
362 {
363 /*
364 * tempting to make remove be recursive, but this is a filesystem,
365 * so best to opt for least surprise
366 */
367 int32_t r = 0, e;
368
369 if (!cgm_dbus_connect()) {
370 return false;
371 }
372
373 if ( cgmanager_remove_sync(NULL, cgroup_manager, controller, cg, r, &e) != 0) {
374 NihError *nerr;
375 nerr = nih_error_get();
376 fprintf(stderr, "call to remove (%s:%s) failed: %s\n", controller, cg, nerr->message);
377 nih_free(nerr);
378 cgm_dbus_disconnect();
379 return false;
380 }
381
382 cgm_dbus_disconnect();
383 return true;
384 }