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",
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", 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", 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", 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 failed: %s", 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 failed: %s", 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 failed: %s", 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 failed: %s", nerr
->message
);
200 cgm_dbus_disconnect();
204 cgm_dbus_disconnect();
208 bool cgm_get_value(const char *controller
, const char *cgroup
, const char *file
,
211 if (!cgm_dbus_connect()) {
215 if ( cgmanager_get_value_sync(NULL
, cgroup_manager
, controller
, cgroup
,
216 file
, value
) != 0 ) {
218 nerr
= nih_error_get();
219 fprintf(stderr
, "call to get_value failed: %s", nerr
->message
);
221 cgm_dbus_disconnect();
225 cgm_dbus_disconnect();
229 bool cgm_set_value(const char *controller
, const char *cgroup
, const char *file
,
232 if (!cgm_dbus_connect()) {
236 if ( cgmanager_set_value_sync(NULL
, cgroup_manager
, controller
, cgroup
,
237 file
, value
) != 0 ) {
239 nerr
= nih_error_get();
240 fprintf(stderr
, "call to set_value failed: %s", nerr
->message
);
242 cgm_dbus_disconnect();
246 cgm_dbus_disconnect();
250 static int wait_for_pid(pid_t pid
)
255 ret
= waitpid(pid
, &status
, 0);
263 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0)
268 bool cgm_create(const char *controller
, const char *cg
, uid_t uid
, gid_t gid
)
274 if (wait_for_pid(pid
) != 0)
279 if (setgroups(0, NULL
))
281 if (setresgid(gid
, gid
, gid
))
283 if (setresuid(uid
, uid
, uid
))
286 if (!cgm_dbus_connect()) {
290 if ( cgmanager_create_sync(NULL
, cgroup_manager
, controller
, cg
, &e
) != 0) {
292 nerr
= nih_error_get();
293 fprintf(stderr
, "call to create failed: %s", nerr
->message
);
295 cgm_dbus_disconnect();
299 cgm_dbus_disconnect();
303 bool cgm_chown_file(const char *controller
, const char *cg
, uid_t uid
, gid_t gid
)
305 if (!cgm_dbus_connect()) {
309 if ( cgmanager_chown_sync(NULL
, cgroup_manager
, controller
, cg
, uid
, gid
) != 0) {
311 nerr
= nih_error_get();
312 fprintf(stderr
, "call to chown failed: %s", nerr
->message
);
314 cgm_dbus_disconnect();
318 cgm_dbus_disconnect();
322 bool cgm_chmod_file(const char *controller
, const char *file
, mode_t mode
)
324 if (!cgm_dbus_connect()) {
328 if ( cgmanager_chmod_sync(NULL
, cgroup_manager
, controller
, file
, "", mode
) != 0) {
330 nerr
= nih_error_get();
331 fprintf(stderr
, "call to chmod failed: %s", nerr
->message
);
333 cgm_dbus_disconnect();
337 cgm_dbus_disconnect();
341 bool cgm_remove(const char *controller
, const char *cg
)
344 * tempting to make remove be recursive, but this is a filesystem,
345 * so best to opt for least surprise
349 if (!cgm_dbus_connect()) {
353 if ( cgmanager_remove_sync(NULL
, cgroup_manager
, controller
, cg
, r
, &e
) != 0) {
355 nerr
= nih_error_get();
356 fprintf(stderr
, "call to remove failed: %s", nerr
->message
);
358 cgm_dbus_disconnect();
362 cgm_dbus_disconnect();