]> git.proxmox.com Git - mirror_lxcfs.git/blob - cgmanager.c
Implement mkdir
[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",
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", 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", 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", 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 failed: %s", 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 failed: %s", 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 failed: %s", 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 failed: %s", 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_get_value(const char *controller, const char *cgroup, const char *file,
209 char **value)
210 {
211 if (!cgm_dbus_connect()) {
212 return false;
213 }
214
215 if ( cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup,
216 file, value) != 0 ) {
217 NihError *nerr;
218 nerr = nih_error_get();
219 fprintf(stderr, "call to get_value failed: %s", nerr->message);
220 nih_free(nerr);
221 cgm_dbus_disconnect();
222 return false;
223 }
224
225 cgm_dbus_disconnect();
226 return true;
227 }
228
229 static int wait_for_pid(pid_t pid)
230 {
231 int status, ret;
232
233 again:
234 ret = waitpid(pid, &status, 0);
235 if (ret == -1) {
236 if (errno == EINTR)
237 goto again;
238 return -1;
239 }
240 if (ret != pid)
241 goto again;
242 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
243 return -1;
244 return 0;
245 }
246
247 bool cgm_create(const char *controller, const char *cg, uid_t uid, gid_t gid)
248 {
249 int32_t e;
250 pid_t pid = fork();
251
252 if (pid) {
253 if (wait_for_pid(pid) != 0)
254 return false;
255 return true;
256 }
257
258 if (setgroups(0, NULL))
259 exit(1);
260 if (setresgid(gid, gid, gid))
261 exit(1);
262 if (setresuid(uid, uid, uid))
263 exit(1);
264
265 if (!cgm_dbus_connect()) {
266 exit(1);
267 }
268
269 if ( cgmanager_create_sync(NULL, cgroup_manager, controller, cg, &e) != 0) {
270 NihError *nerr;
271 nerr = nih_error_get();
272 fprintf(stderr, "call to create failed: %s", nerr->message);
273 nih_free(nerr);
274 cgm_dbus_disconnect();
275 exit(1);
276 }
277
278 cgm_dbus_disconnect();
279 exit(0);
280 }
281
282 #if 0
283 bool cgm_chown(const char *controller, const char *cg, uid_t uid, gid_t gid)
284 {
285 if (!cgm_dbus_connect()) {
286 return false;
287 }
288
289 if ( cgmanager_chown_sync(NULL, cgroup_manager, controller, cg, uid, gid) != 0) {
290 NihError *nerr;
291 nerr = nih_error_get();
292 fprintf(stderr, "call to chown failed: %s", nerr->message);
293 nih_free(nerr);
294 cgm_dbus_disconnect();
295 return false;
296 }
297
298 cgm_dbus_disconnect();
299 return true;
300 }
301
302 bool cgm_remove(const char *controller, const char *cg)
303 {
304 int32_t r = 1, e;
305
306 if (!cgm_dbus_connect()) {
307 return false;
308 }
309
310 if ( cgmanager_remove_sync(NULL, cgroup_manager, controller, cg, r, &e) != 0) {
311 NihError *nerr;
312 nerr = nih_error_get();
313 fprintf(stderr, "call to remove failed: %s", nerr->message);
314 nih_free(nerr);
315 cgm_dbus_disconnect();
316 return false;
317 }
318
319 cgm_dbus_disconnect();
320 return true;
321 }
322 #endif