removing svn keyword $Id$ from all files
[strongswan.git] / src / dumm / dumm.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * 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 <debug.h>
27 #include <utils/linked_list.h>
28
29 #include "dumm.h"
30
31 #define PERME (S_IRWXU | S_IRWXG)
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 /**
53 * Implementation of dumm_t.create_guest.
54 */
55 static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
56 char *master, char *args)
57 {
58 guest_t *guest;
59
60 guest = guest_create(this->guest_dir, name, kernel, master, args);
61 if (guest)
62 {
63 this->guests->insert_last(this->guests, guest);
64 }
65 return guest;
66 }
67
68 /**
69 * Implementation of dumm_t.create_guest_enumerator.
70 */
71 static enumerator_t* create_guest_enumerator(private_dumm_t *this)
72 {
73 return this->guests->create_enumerator(this->guests);
74 }
75
76 /**
77 * Implementation of dumm_t.delete_guest.
78 */
79 static void delete_guest(private_dumm_t *this, guest_t *guest)
80 {
81 if (this->guests->remove(this->guests, guest, NULL))
82 {
83 char buf[512];
84 int len;
85
86 len = snprintf(buf, sizeof(buf), "rm -Rf %s/%s",
87 this->guest_dir, guest->get_name(guest));
88 guest->destroy(guest);
89 if (len > 8 && len < 512)
90 {
91 ignore_result(system(buf));
92 }
93 }
94 }
95
96 /**
97 * Implementation of dumm_t.create_bridge.
98 */
99 static bridge_t* create_bridge(private_dumm_t *this, char *name)
100 {
101 bridge_t *bridge;
102
103 bridge = bridge_create(name);
104 if (bridge)
105 {
106 this->bridges->insert_last(this->bridges, bridge);
107 }
108 return bridge;
109 }
110
111 /**
112 * Implementation of dumm_t.create_bridge_enumerator.
113 */
114 static enumerator_t* create_bridge_enumerator(private_dumm_t *this)
115 {
116 return this->bridges->create_enumerator(this->bridges);
117 }
118
119 /**
120 * Implementation of dumm_t.delete_bridge.
121 */
122 static void delete_bridge(private_dumm_t *this, bridge_t *bridge)
123 {
124 if (this->bridges->remove(this->bridges, bridge, NULL))
125 {
126 bridge->destroy(bridge);
127 }
128 }
129
130 /**
131 * disable the currently enabled template
132 */
133 static void clear_template(private_dumm_t *this)
134 {
135 enumerator_t *enumerator;
136 guest_t *guest;
137
138 free(this->template);
139 this->template = NULL;
140
141 enumerator = this->guests->create_enumerator(this->guests);
142 while (enumerator->enumerate(enumerator, (void**)&guest))
143 {
144 guest->load_template(guest, NULL);
145 }
146 enumerator->destroy(enumerator);
147 }
148
149 /**
150 * Implementation of dumm_t.load_template.
151 */
152 static bool load_template(private_dumm_t *this, char *dir)
153 {
154 enumerator_t *enumerator;
155 guest_t *guest;
156
157 clear_template(this);
158
159 if (dir == NULL)
160 {
161 return TRUE;
162 }
163 if (strlen(dir) > PATH_MAX)
164 {
165 DBG1("template directory string '%s' is too long", dir);
166 return FALSE;
167 }
168
169 if (asprintf(&this->template, "%s/%s", TEMPLATE_DIR, dir) < 0)
170 {
171 this->template = NULL;
172 return FALSE;
173 }
174 if (access(this->template, F_OK) != 0)
175 { /* does not exist, create template */
176 if (!mkdir_p(this->template, PERME))
177 {
178 DBG1("creating template directory '%s' failed: %m", this->template);
179 return FALSE;
180 }
181 }
182 enumerator = this->guests->create_enumerator(this->guests);
183 while (enumerator->enumerate(enumerator, (void**)&guest))
184 {
185 if (!guest->load_template(guest, this->template))
186 {
187 enumerator->destroy(enumerator);
188 clear_template(this);
189 return FALSE;
190 }
191 }
192 enumerator->destroy(enumerator);
193 return TRUE;
194 }
195
196 /**
197 * Implementation of dumm_t.destroy
198 */
199 static void destroy(private_dumm_t *this)
200 {
201 enumerator_t *enumerator;
202 guest_t *guest;
203
204 this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
205
206 enumerator = this->guests->create_enumerator(this->guests);
207 while (enumerator->enumerate(enumerator, (void**)&guest))
208 {
209 guest->stop(guest, NULL);
210 }
211 enumerator->destroy(enumerator);
212
213 while (this->guests->remove_last(this->guests, (void**)&guest) == SUCCESS)
214 {
215 guest->destroy(guest);
216 }
217 this->guests->destroy(this->guests);
218 free(this->guest_dir);
219 free(this->template);
220 free(this->dir);
221 free(this);
222 }
223
224 /**
225 * load all guests in our working dir
226 */
227 static void load_guests(private_dumm_t *this)
228 {
229 DIR *dir;
230 struct dirent *ent;
231 guest_t *guest;
232
233 dir = opendir(this->guest_dir);
234 if (dir == NULL)
235 {
236 return;
237 }
238
239 while ((ent = readdir(dir)))
240 {
241 if (*ent->d_name == '.')
242 { /* skip ".", ".." and hidden files (such as ".svn") */
243 continue;
244 }
245 guest = guest_load(this->guest_dir, ent->d_name);
246 if (guest)
247 {
248 this->guests->insert_last(this->guests, guest);
249 }
250 else
251 {
252 DBG1("loading guest in directory '%s' failed, skipped", ent->d_name);
253 }
254 }
255 closedir(dir);
256 }
257
258 /**
259 * create a dumm instance
260 */
261 dumm_t *dumm_create(char *dir)
262 {
263 char cwd[PATH_MAX];
264 private_dumm_t *this = malloc_thing(private_dumm_t);
265
266 this->public.create_guest = (guest_t*(*)(dumm_t*,char*,char*,char*,char*))create_guest;
267 this->public.create_guest_enumerator = (enumerator_t*(*)(dumm_t*))create_guest_enumerator;
268 this->public.delete_guest = (void(*)(dumm_t*,guest_t*))delete_guest;
269 this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
270 this->public.create_bridge_enumerator = (enumerator_t*(*)(dumm_t*))create_bridge_enumerator;
271 this->public.delete_bridge = (void(*)(dumm_t*,bridge_t*))delete_bridge;
272 this->public.load_template = (bool(*)(dumm_t*, char *name))load_template;
273 this->public.destroy = (void(*)(dumm_t*))destroy;
274
275 if (dir && *dir == '/')
276 {
277 this->dir = strdup(dir);
278 }
279 else
280 {
281 if (getcwd(cwd, sizeof(cwd)) == NULL)
282 {
283 free(this);
284 return NULL;
285 }
286 if (dir)
287 {
288 if (asprintf(&this->dir, "%s/%s", cwd, dir) < 0)
289 {
290 this->dir = NULL;
291 }
292 }
293 else
294 {
295 this->dir = strdup(cwd);
296 }
297 }
298 this->template = NULL;
299 if (asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR) < 0)
300 {
301 this->guest_dir = NULL;
302 }
303 this->guests = linked_list_create();
304 this->bridges = linked_list_create();
305
306 if (this->dir == NULL || this->guest_dir == NULL ||
307 (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST))
308 {
309 DBG1("creating guest directory '%s' failed: %m", this->guest_dir);
310 destroy(this);
311 return NULL;
312 }
313
314 load_guests(this);
315 return &this->public;
316 }
317