]> git.proxmox.com Git - mirror_lxcfs.git/blame - cgmanager.c
implement rmdir
[mirror_lxcfs.git] / cgmanager.c
CommitLineData
2183082c
SH
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>
ab54b798 42#include <sys/wait.h>
2183082c
SH
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
55static NihDBusProxy *cgroup_manager = NULL;
56static int32_t api_version;
57
58static 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"
69static 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
110bool 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
129bool 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
149bool 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
168char *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
189bool 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}
99978832
SH
207
208bool 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}
ab54b798 228
2ad6d2bd
SH
229bool 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
ab54b798
SH
250static int wait_for_pid(pid_t pid)
251{
252 int status, ret;
253
254again:
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
268bool 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
341b21ad 303bool cgm_chown_file(const char *controller, const char *cg, uid_t uid, gid_t gid)
ab54b798
SH
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
322bool cgm_remove(const char *controller, const char *cg)
323{
50d8d5b5
SH
324 /*
325 * tempting to make remove be recursive, but this is a filesystem,
326 * so best to opt for least surprise
327 */
328 int32_t r = 0, e;
ab54b798
SH
329
330 if (!cgm_dbus_connect()) {
331 return false;
332 }
333
334 if ( cgmanager_remove_sync(NULL, cgroup_manager, controller, cg, r, &e) != 0) {
335 NihError *nerr;
336 nerr = nih_error_get();
337 fprintf(stderr, "call to remove failed: %s", nerr->message);
338 nih_free(nerr);
339 cgm_dbus_disconnect();
340 return false;
341 }
342
343 cgm_dbus_disconnect();
344 return true;
345}