]> git.proxmox.com Git - mirror_lxcfs.git/blob - cgmanager.c
implement chmod
[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 bool cgm_set_value(const char *controller, const char *cgroup, const char *file,
230 const char *value)
231 {
232 if (!cgm_dbus_connect()) {
233 return false;
234 }
235
236 if ( cgmanager_set_value_sync(NULL, cgroup_manager, controller, cgroup,
237 file, value) != 0 ) {
238 NihError *nerr;
239 nerr = nih_error_get();
240 fprintf(stderr, "call to set_value failed: %s", nerr->message);
241 nih_free(nerr);
242 cgm_dbus_disconnect();
243 return false;
244 }
245
246 cgm_dbus_disconnect();
247 return true;
248 }
249
250 static int wait_for_pid(pid_t pid)
251 {
252 int status, ret;
253
254 again:
255 ret = waitpid(pid, &status, 0);
256 if (ret == -1) {
257 if (errno == EINTR)
258 goto again;
259 return -1;
260 }
261 if (ret != pid)
262 goto again;
263 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
264 return -1;
265 return 0;
266 }
267
268 bool cgm_create(const char *controller, const char *cg, uid_t uid, gid_t gid)
269 {
270 int32_t e;
271 pid_t pid = fork();
272
273 if (pid) {
274 if (wait_for_pid(pid) != 0)
275 return false;
276 return true;
277 }
278
279 if (setgroups(0, NULL))
280 exit(1);
281 if (setresgid(gid, gid, gid))
282 exit(1);
283 if (setresuid(uid, uid, uid))
284 exit(1);
285
286 if (!cgm_dbus_connect()) {
287 exit(1);
288 }
289
290 if ( cgmanager_create_sync(NULL, cgroup_manager, controller, cg, &e) != 0) {
291 NihError *nerr;
292 nerr = nih_error_get();
293 fprintf(stderr, "call to create failed: %s", nerr->message);
294 nih_free(nerr);
295 cgm_dbus_disconnect();
296 exit(1);
297 }
298
299 cgm_dbus_disconnect();
300 exit(0);
301 }
302
303 bool cgm_chown_file(const char *controller, const char *cg, uid_t uid, gid_t gid)
304 {
305 if (!cgm_dbus_connect()) {
306 return false;
307 }
308
309 if ( cgmanager_chown_sync(NULL, cgroup_manager, controller, cg, uid, gid) != 0) {
310 NihError *nerr;
311 nerr = nih_error_get();
312 fprintf(stderr, "call to chown failed: %s", nerr->message);
313 nih_free(nerr);
314 cgm_dbus_disconnect();
315 return false;
316 }
317
318 cgm_dbus_disconnect();
319 return true;
320 }
321
322 bool cgm_chmod_file(const char *controller, const char *file, mode_t mode)
323 {
324 if (!cgm_dbus_connect()) {
325 return false;
326 }
327
328 if ( cgmanager_chmod_sync(NULL, cgroup_manager, controller, file, "", mode) != 0) {
329 NihError *nerr;
330 nerr = nih_error_get();
331 fprintf(stderr, "call to chmod failed: %s", nerr->message);
332 nih_free(nerr);
333 cgm_dbus_disconnect();
334 return false;
335 }
336
337 cgm_dbus_disconnect();
338 return true;
339 }
340
341 bool cgm_remove(const char *controller, const char *cg)
342 {
343 /*
344 * tempting to make remove be recursive, but this is a filesystem,
345 * so best to opt for least surprise
346 */
347 int32_t r = 0, e;
348
349 if (!cgm_dbus_connect()) {
350 return false;
351 }
352
353 if ( cgmanager_remove_sync(NULL, cgroup_manager, controller, cg, r, &e) != 0) {
354 NihError *nerr;
355 nerr = nih_error_get();
356 fprintf(stderr, "call to remove failed: %s", nerr->message);
357 nih_free(nerr);
358 cgm_dbus_disconnect();
359 return false;
360 }
361
362 cgm_dbus_disconnect();
363 return true;
364 }