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