2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
5 * (C) Copyright Canonical, Inc, 2014
8 * Daniel Lezcano <daniel.lezcano at free.fr>
9 * Serge Hallyn <serge.hallyn@ubuntu.com>
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.
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.
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
37 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/inotify.h>
41 #include <sys/mount.h>
43 #include <netinet/in.h>
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>
53 #include "cgmanager.h"
55 static NihDBusProxy
*cgroup_manager
= NULL
;
56 static int32_t api_version
;
58 static void cgm_dbus_disconnect(void)
61 dbus_connection_flush(cgroup_manager
->connection
);
62 dbus_connection_close(cgroup_manager
->connection
);
63 nih_free(cgroup_manager
);
65 cgroup_manager
= NULL
;
68 #define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
69 static bool cgm_dbus_connect(void)
72 static DBusConnection
*connection
;
74 dbus_error_init(&dbus_error
);
76 connection
= dbus_connection_open_private(CGMANAGER_DBUS_SOCK
, &dbus_error
);
78 fprintf(stderr
, "Failed opening dbus connection: %s: %s\n",
79 dbus_error
.name
, dbus_error
.message
);
80 dbus_error_free(&dbus_error
);
83 dbus_connection_set_exit_on_disconnect(connection
, FALSE
);
84 dbus_error_free(&dbus_error
);
85 cgroup_manager
= nih_dbus_proxy_new(NULL
, connection
,
87 "/org/linuxcontainers/cgmanager", NULL
, NULL
);
88 dbus_connection_unref(connection
);
89 if (!cgroup_manager
) {
91 nerr
= nih_error_get();
92 fprintf(stderr
, "Error opening cgmanager proxy: %s\n", nerr
->message
);
94 cgm_dbus_disconnect();
98 // get the api version
99 if (cgmanager_get_api_version_sync(NULL
, cgroup_manager
, &api_version
) != 0) {
101 nerr
= nih_error_get();
102 fprintf(stderr
, "Error cgroup manager api version: %s\n", nerr
->message
);
104 cgm_dbus_disconnect();
110 bool cgm_get_controllers(char ***contrls
)
112 if (!cgm_dbus_connect()) {
116 if ( cgmanager_list_controllers_sync(NULL
, cgroup_manager
, contrls
) != 0 ) {
118 nerr
= nih_error_get();
119 fprintf(stderr
, "call to list_controllers failed: %s\n", nerr
->message
);
121 cgm_dbus_disconnect();
125 cgm_dbus_disconnect();
129 bool cgm_list_keys(const char *controller
, const char *cgroup
, struct cgm_keys
***keys
)
131 if (!cgm_dbus_connect()) {
135 if ( cgmanager_list_keys_sync(NULL
, cgroup_manager
, controller
, cgroup
,
136 (CgmanagerListKeysOutputElement
***)keys
) != 0 ) {
138 nerr
= nih_error_get();
139 fprintf(stderr
, "call to list_keys (%s:%s) failed: %s\n", controller
, cgroup
, nerr
->message
);
141 cgm_dbus_disconnect();
145 cgm_dbus_disconnect();
149 bool cgm_list_children(const char *controller
, const char *cgroup
, char ***list
)
151 if (!cgm_dbus_connect()) {
155 if ( cgmanager_list_children_sync(NULL
, cgroup_manager
, controller
, cgroup
, list
) != 0 ) {
157 nerr
= nih_error_get();
158 fprintf(stderr
, "call to list_children (%s:%s) failed: %s\n", controller
, cgroup
, nerr
->message
);
160 cgm_dbus_disconnect();
164 cgm_dbus_disconnect();
168 char *cgm_get_pid_cgroup(pid_t pid
, const char *controller
)
172 if (!cgm_dbus_connect()) {
176 if ( cgmanager_get_pid_cgroup_sync(NULL
, cgroup_manager
, controller
, pid
, &output
) != 0 ) {
178 nerr
= nih_error_get();
179 fprintf(stderr
, "call to get_pid_cgroup (%s) failed: %s\n", controller
, nerr
->message
);
181 cgm_dbus_disconnect();
185 cgm_dbus_disconnect();
189 bool cgm_escape_cgroup(void)
191 if (!cgm_dbus_connect()) {
195 if ( cgmanager_move_pid_abs_sync(NULL
, cgroup_manager
, "all", "/", (int32_t) getpid()) != 0 ) {
197 nerr
= nih_error_get();
198 fprintf(stderr
, "call to move_pid_abs (all:/) failed: %s\n", nerr
->message
);
200 cgm_dbus_disconnect();
204 cgm_dbus_disconnect();
208 bool cgm_move_pid(const char *controller
, const char *cgroup
, pid_t pid
)
210 if (!cgm_dbus_connect()) {
214 if ( cgmanager_move_pid_sync(NULL
, cgroup_manager
, controller
, cgroup
,
215 (int32_t) pid
) != 0 ) {
217 nerr
= nih_error_get();
218 fprintf(stderr
, "call to move_pid (%s:%s, %d) failed: %s\n", controller
, cgroup
, pid
, nerr
->message
);
220 cgm_dbus_disconnect();
224 cgm_dbus_disconnect();
228 bool cgm_get_value(const char *controller
, const char *cgroup
, const char *file
,
231 if (!cgm_dbus_connect()) {
235 if ( cgmanager_get_value_sync(NULL
, cgroup_manager
, controller
, cgroup
,
236 file
, value
) != 0 ) {
238 nerr
= nih_error_get();
239 fprintf(stderr
, "call to get_value (%s:%s, %s) failed: %s\n", controller
, cgroup
, file
, nerr
->message
);
241 cgm_dbus_disconnect();
245 cgm_dbus_disconnect();
249 bool cgm_set_value(const char *controller
, const char *cgroup
, const char *file
,
252 if (!cgm_dbus_connect()) {
256 if ( cgmanager_set_value_sync(NULL
, cgroup_manager
, controller
, cgroup
,
257 file
, value
) != 0 ) {
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
);
262 cgm_dbus_disconnect();
266 cgm_dbus_disconnect();
270 static int wait_for_pid(pid_t pid
)
275 ret
= waitpid(pid
, &status
, 0);
283 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0)
288 bool cgm_create(const char *controller
, const char *cg
, uid_t uid
, gid_t gid
)
294 if (wait_for_pid(pid
) != 0)
299 if (setgroups(0, NULL
))
301 if (setresgid(gid
, gid
, gid
))
303 if (setresuid(uid
, uid
, uid
))
306 if (!cgm_dbus_connect()) {
310 if ( cgmanager_create_sync(NULL
, cgroup_manager
, controller
, cg
, &e
) != 0) {
312 nerr
= nih_error_get();
313 fprintf(stderr
, "call to create failed (%s:%s): %s\n", controller
, cg
, nerr
->message
);
315 cgm_dbus_disconnect();
319 cgm_dbus_disconnect();
323 bool cgm_chown_file(const char *controller
, const char *cg
, uid_t uid
, gid_t gid
)
325 if (!cgm_dbus_connect()) {
329 if ( cgmanager_chown_sync(NULL
, cgroup_manager
, controller
, cg
, uid
, gid
) != 0) {
331 nerr
= nih_error_get();
332 fprintf(stderr
, "call to chown (%s:%s, %d, %d) failed: %s\n", controller
, cg
, uid
, gid
, nerr
->message
);
334 cgm_dbus_disconnect();
338 cgm_dbus_disconnect();
342 bool cgm_chmod_file(const char *controller
, const char *file
, mode_t mode
)
344 if (!cgm_dbus_connect()) {
348 if ( cgmanager_chmod_sync(NULL
, cgroup_manager
, controller
, file
, "", mode
) != 0) {
350 nerr
= nih_error_get();
351 fprintf(stderr
, "call to chmod (%s:%s, %d) failed: %s\n", controller
, file
, mode
, nerr
->message
);
353 cgm_dbus_disconnect();
357 cgm_dbus_disconnect();
361 bool cgm_remove(const char *controller
, const char *cg
)
364 * tempting to make remove be recursive, but this is a filesystem,
365 * so best to opt for least surprise
369 if (!cgm_dbus_connect()) {
373 if ( cgmanager_remove_sync(NULL
, cgroup_manager
, controller
, cg
, r
, &e
) != 0) {
375 nerr
= nih_error_get();
376 fprintf(stderr
, "call to remove (%s:%s) failed: %s\n", controller
, cg
, nerr
->message
);
378 cgm_dbus_disconnect();
382 cgm_dbus_disconnect();