]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/dumm/dumm.c
android: Properly set log file path
[thirdparty/strongswan.git] / src / dumm / dumm.c
1 /*
2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <dirent.h>
24 #include <errno.h>
25
26 #include <utils/debug.h>
27 #include <collections/linked_list.h>
28
29 #include "dumm.h"
30
31 #define PERME (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
32 #define GUEST_DIR "guests"
33 #define TEMPLATE_DIR "templates"
34
35 typedef struct private_dumm_t private_dumm_t;
36
37 struct private_dumm_t {
38 /** public dumm interface */
39 dumm_t public;
40 /** working dir */
41 char *dir;
42 /** directory of guests */
43 char *guest_dir;
44 /** directory of loaded template */
45 char *template;
46 /** list of managed guests */
47 linked_list_t *guests;
48 /** list of managed bridges */
49 linked_list_t *bridges;
50 };
51
52 METHOD(dumm_t, create_guest, guest_t*,
53 private_dumm_t *this, char *name, char *kernel, char *master, char *args)
54 {
55 guest_t *guest;
56
57 guest = guest_create(this->guest_dir, name, kernel, master, args);
58 if (guest)
59 {
60 this->guests->insert_last(this->guests, guest);
61 }
62 return guest;
63 }
64
65 METHOD(dumm_t, create_guest_enumerator, enumerator_t*,
66 private_dumm_t *this)
67 {
68 return this->guests->create_enumerator(this->guests);
69 }
70
71 METHOD(dumm_t, delete_guest, void,
72 private_dumm_t *this, guest_t *guest)
73 {
74 if (this->guests->remove(this->guests, guest, NULL))
75 {
76 char buf[512];
77 int len;
78
79 len = snprintf(buf, sizeof(buf), "rm -Rf %s/%s",
80 this->guest_dir, guest->get_name(guest));
81 guest->destroy(guest);
82 if (len > 8 && len < 512)
83 {
84 ignore_result(system(buf));
85 }
86 }
87 }
88
89 METHOD(dumm_t, create_bridge, bridge_t*,
90 private_dumm_t *this, char *name)
91 {
92 bridge_t *bridge;
93
94 bridge = bridge_create(name);
95 if (bridge)
96 {
97 this->bridges->insert_last(this->bridges, bridge);
98 }
99 return bridge;
100 }
101
102 METHOD(dumm_t, create_bridge_enumerator, enumerator_t*,
103 private_dumm_t *this)
104 {
105 return this->bridges->create_enumerator(this->bridges);
106 }
107
108 METHOD(dumm_t, delete_bridge, void,
109 private_dumm_t *this, bridge_t *bridge)
110 {
111 if (this->bridges->remove(this->bridges, bridge, NULL))
112 {
113 bridge->destroy(bridge);
114 }
115 }
116
117 METHOD(dumm_t, add_overlay, bool,
118 private_dumm_t *this, char *dir)
119 {
120 enumerator_t *enumerator;
121 guest_t *guest;
122
123 if (dir == NULL)
124 {
125 return TRUE;
126 }
127 if (strlen(dir) > PATH_MAX)
128 {
129 DBG1(DBG_LIB, "overlay directory string '%s' is too long", dir);
130 return FALSE;
131 }
132 if (access(dir, F_OK) != 0)
133 {
134 if (!mkdir_p(dir, PERME))
135 {
136 DBG1(DBG_LIB, "creating overlay directory '%s' failed: %m", dir);
137 return FALSE;
138 }
139 }
140 enumerator = this->guests->create_enumerator(this->guests);
141 while (enumerator->enumerate(enumerator, (void**)&guest))
142 {
143 char guest_dir[PATH_MAX];
144 int len = snprintf(guest_dir, sizeof(guest_dir), "%s/%s", dir,
145 guest->get_name(guest));
146 if (len < 0 || len >= sizeof(guest_dir))
147 {
148 goto error;
149 }
150 if (access(guest_dir, F_OK) != 0)
151 {
152 if (!mkdir_p(guest_dir, PERME))
153 {
154 DBG1(DBG_LIB, "creating overlay directory for guest '%s' failed: %m",
155 guest->get_name(guest));
156 goto error;
157 }
158 }
159 if (!guest->add_overlay(guest, guest_dir))
160 {
161 goto error;
162 }
163 }
164 enumerator->destroy(enumerator);
165 return TRUE;
166 error:
167 enumerator->destroy(enumerator);
168 this->public.del_overlay(&this->public, dir);
169 return FALSE;
170 }
171
172 METHOD(dumm_t, del_overlay, bool,
173 private_dumm_t *this, char *dir)
174 {
175 bool ret = FALSE;
176 enumerator_t *enumerator;
177 guest_t *guest;
178
179 enumerator = this->guests->create_enumerator(this->guests);
180 while (enumerator->enumerate(enumerator, (void**)&guest))
181 {
182 char guest_dir[PATH_MAX];
183 int len = snprintf(guest_dir, sizeof(guest_dir), "%s/%s", dir,
184 guest->get_name(guest));
185 if (len < 0 || len >= sizeof(guest_dir))
186 {
187 continue;
188 }
189 ret = guest->del_overlay(guest, guest_dir) || ret;
190 }
191 enumerator->destroy(enumerator);
192 return ret;
193 }
194
195 METHOD(dumm_t, pop_overlay, bool,
196 private_dumm_t *this)
197 {
198 bool ret = FALSE;
199 enumerator_t *enumerator;
200 guest_t *guest;
201
202 enumerator = this->guests->create_enumerator(this->guests);
203 while (enumerator->enumerate(enumerator, (void**)&guest))
204 {
205 ret = guest->pop_overlay(guest) || ret;
206 }
207 enumerator->destroy(enumerator);
208 return ret;
209 }
210
211 /**
212 * disable the currently enabled template
213 */
214 static void clear_template(private_dumm_t *this)
215 {
216 if (this->template)
217 {
218 del_overlay(this, this->template);
219 free(this->template);
220 this->template = NULL;
221 }
222 }
223
224 METHOD(dumm_t, load_template, bool,
225 private_dumm_t *this, char *name)
226 {
227 clear_template(this);
228 if (name == NULL)
229 {
230 return TRUE;
231 }
232 if (strlen(name) > PATH_MAX)
233 {
234 DBG1(DBG_LIB, "template name '%s' is too long", name);
235 return FALSE;
236 }
237 if (strchr(name, '/') != NULL)
238 {
239 DBG1(DBG_LIB, "template name '%s' must not contain '/' characters", name);
240 return FALSE;
241 }
242 if (asprintf(&this->template, "%s/%s", TEMPLATE_DIR, name) < 0)
243 {
244 this->template = NULL;
245 return FALSE;
246 }
247 if (access(this->template, F_OK) != 0)
248 {
249 if (!mkdir_p(this->template, PERME))
250 {
251 DBG1(DBG_LIB, "creating template directory '%s' failed: %m",
252 this->template);
253 return FALSE;
254 }
255 }
256 return add_overlay(this, this->template);
257 }
258
259 /**
260 * Template directory enumerator
261 */
262 typedef struct {
263 /** implements enumerator_t */
264 enumerator_t public;
265 /** directory enumerator */
266 enumerator_t *inner;
267 } template_enumerator_t;
268
269 METHOD(enumerator_t, template_enumerate, bool,
270 template_enumerator_t *this, va_list args)
271 {
272 struct stat st;
273 char *rel, **template;
274
275 VA_ARGS_VGET(args, template);
276
277 while (this->inner->enumerate(this->inner, &rel, NULL, &st))
278 {
279 if (S_ISDIR(st.st_mode) && *rel != '.')
280 {
281 *template = rel;
282 return TRUE;
283 }
284 }
285 return FALSE;
286 }
287
288 METHOD(enumerator_t, template_enumerator_destroy, void,
289 template_enumerator_t *this)
290 {
291 this->inner->destroy(this->inner);
292 free(this);
293 }
294
295 METHOD(dumm_t, create_template_enumerator, enumerator_t*,
296 private_dumm_t *this)
297 {
298 template_enumerator_t *enumerator;
299 INIT(enumerator,
300 .public = {
301 .enumerate = enumerator_enumerate_default,
302 .venumerate = _template_enumerate,
303 .destroy = (void*)_template_enumerator_destroy,
304 },
305 .inner = enumerator_create_directory(TEMPLATE_DIR),
306 );
307 if (!enumerator->inner)
308 {
309 free(enumerator);
310 return enumerator_create_empty();
311 }
312 return &enumerator->public;
313 }
314
315 METHOD(dumm_t, destroy, void,
316 private_dumm_t *this)
317 {
318 enumerator_t *enumerator;
319 guest_t *guest;
320
321 this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
322
323 enumerator = this->guests->create_enumerator(this->guests);
324 while (enumerator->enumerate(enumerator, (void**)&guest))
325 {
326 guest->stop(guest, NULL);
327 }
328 enumerator->destroy(enumerator);
329
330 while (this->guests->remove_last(this->guests, (void**)&guest) == SUCCESS)
331 {
332 guest->destroy(guest);
333 }
334 this->guests->destroy(this->guests);
335 free(this->guest_dir);
336 free(this->template);
337 free(this->dir);
338 free(this);
339 }
340
341 /**
342 * load all guests in our working dir
343 */
344 static void load_guests(private_dumm_t *this)
345 {
346 DIR *dir;
347 struct dirent *ent;
348 guest_t *guest;
349
350 dir = opendir(this->guest_dir);
351 if (dir == NULL)
352 {
353 return;
354 }
355
356 while ((ent = readdir(dir)))
357 {
358 if (*ent->d_name == '.')
359 { /* skip ".", ".." and hidden files (such as ".svn") */
360 continue;
361 }
362 guest = guest_load(this->guest_dir, ent->d_name);
363 if (guest)
364 {
365 this->guests->insert_last(this->guests, guest);
366 }
367 else
368 {
369 DBG1(DBG_LIB, "loading guest in directory '%s' failed, skipped",
370 ent->d_name);
371 }
372 }
373 closedir(dir);
374 }
375
376 /**
377 * create a dumm instance
378 */
379 dumm_t *dumm_create(char *dir)
380 {
381 char cwd[PATH_MAX];
382 private_dumm_t *this;
383
384 INIT(this,
385 .public = {
386 .create_guest = _create_guest,
387 .create_guest_enumerator = _create_guest_enumerator,
388 .delete_guest = _delete_guest,
389 .create_bridge = _create_bridge,
390 .create_bridge_enumerator = _create_bridge_enumerator,
391 .delete_bridge = _delete_bridge,
392 .add_overlay = _add_overlay,
393 .del_overlay = _del_overlay,
394 .pop_overlay = _pop_overlay,
395 .load_template = _load_template,
396 .create_template_enumerator = _create_template_enumerator,
397 .destroy = _destroy,
398 },
399 );
400
401 if (dir && *dir == '/')
402 {
403 this->dir = strdup(dir);
404 }
405 else
406 {
407 if (getcwd(cwd, sizeof(cwd)) == NULL)
408 {
409 free(this);
410 return NULL;
411 }
412 if (dir)
413 {
414 if (asprintf(&this->dir, "%s/%s", cwd, dir) < 0)
415 {
416 this->dir = NULL;
417 }
418 }
419 else
420 {
421 this->dir = strdup(cwd);
422 }
423 }
424 if (asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR) < 0)
425 {
426 this->guest_dir = NULL;
427 }
428
429 this->guests = linked_list_create();
430 this->bridges = linked_list_create();
431
432 if (this->dir == NULL || this->guest_dir == NULL ||
433 (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST))
434 {
435 DBG1(DBG_LIB, "creating guest directory '%s' failed: %m",
436 this->guest_dir);
437 destroy(this);
438 return NULL;
439 }
440
441 load_guests(this);
442 return &this->public;
443 }
444