prototype of dumm GUI
[strongswan.git] / src / dumm / dumm.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #define _GNU_SOURCE
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <dirent.h>
23 #include <errno.h>
24
25 #include <debug.h>
26 #include <utils/linked_list.h>
27
28 #include "dumm.h"
29
30 #define PERME (S_IRWXU | S_IRWXG)
31 #define GUEST_DIR "guests"
32 #define TEMPLATE_DIR "templates"
33 #define TEMPLATE_DIR_DIR "diff"
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 templates */
45 char *template_dir;
46 /** directory of loaded template */
47 char *template;
48 /** list of managed guests */
49 linked_list_t *guests;
50 /** list of managed bridges */
51 linked_list_t *bridges;
52 /** do not catch signals if we are destroying */
53 bool destroying;
54 };
55
56 /**
57 * Implementation of dumm_t.create_guest.
58 */
59 static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
60 char *master, int mem)
61 {
62 guest_t *guest;
63
64 guest = guest_create(this->guest_dir, name, kernel, master, mem);
65 if (guest)
66 {
67 this->guests->insert_last(this->guests, guest);
68 }
69 return guest;
70 }
71
72 /**
73 * Implementation of dumm_t.create_guest_enumerator.
74 */
75 static enumerator_t* create_guest_enumerator(private_dumm_t *this)
76 {
77 return this->guests->create_enumerator(this->guests);
78 }
79
80 /**
81 * Implementation of dumm_t.delete_guest.
82 */
83 static void delete_guest(private_dumm_t *this, guest_t *guest)
84 {
85 if (this->guests->remove(this->guests, guest, NULL))
86 {
87 char buf[512];
88 int len;
89
90 len = snprintf(buf, sizeof(buf), "rm -Rf %s/%s",
91 this->guest_dir, guest->get_name(guest));
92 guest->destroy(guest);
93 if (len > 8 && len < 512)
94 {
95 system(buf);
96 }
97 }
98 }
99
100 /**
101 * Implementation of dumm_t.create_bridge.
102 */
103 static bridge_t* create_bridge(private_dumm_t *this, char *name)
104 {
105 bridge_t *bridge;
106
107 bridge = bridge_create(name);
108 if (bridge)
109 {
110 this->bridges->insert_last(this->bridges, bridge);
111 }
112 return bridge;
113 }
114
115 /**
116 * Implementation of dumm_t.create_bridge_enumerator.
117 */
118 static enumerator_t* create_bridge_enumerator(private_dumm_t *this)
119 {
120 return this->bridges->create_enumerator(this->bridges);
121 }
122
123 /**
124 * Implementation of dumm_t.delete_bridge.
125 */
126 static void delete_bridge(private_dumm_t *this, bridge_t *bridge)
127 {
128 if (this->bridges->remove(this->bridges, bridge, NULL))
129 {
130 bridge->destroy(bridge);
131 }
132 }
133
134 /**
135 * disable the currently enabled template
136 */
137 static void clear_template(private_dumm_t *this)
138 {
139 enumerator_t *enumerator;
140 guest_t *guest;
141
142 free(this->template);
143 this->template = NULL;
144
145 enumerator = this->guests->create_enumerator(this->guests);
146 while (enumerator->enumerate(enumerator, (void**)&guest))
147 {
148 guest->load_template(guest, NULL);
149 }
150 enumerator->destroy(enumerator);
151 }
152
153 /**
154 * Implementation of dumm_t.load_template.
155 */
156 static bool load_template(private_dumm_t *this, char *name)
157 {
158 enumerator_t *enumerator;
159 guest_t *guest;
160 char dir[PATH_MAX];
161 size_t len;
162
163 clear_template(this);
164
165 if (name == NULL)
166 {
167 return TRUE;
168 }
169
170 free(this->template);
171 asprintf(&this->template, "%s/%s", this->template_dir, name);
172 len = snprintf(dir, sizeof(dir), "%s/%s", this->template, TEMPLATE_DIR_DIR);
173 if (len < 0 || len >= sizeof(dir))
174 {
175 return FALSE;
176 }
177
178 if (access(this->template, F_OK) != 0)
179 { /* does not exist, create template */
180 if (mkdir(this->template, PERME) != 0)
181 {
182 DBG1("creating template directory '%s' failed: %m", this->template);
183 return FALSE;
184 }
185 if (mkdir(dir, PERME) != 0)
186 {
187 DBG1("creating template overlay directory '%s' failed: %m", dir);
188 return FALSE;
189 }
190 }
191 enumerator = this->guests->create_enumerator(this->guests);
192 while (enumerator->enumerate(enumerator, (void**)&guest))
193 {
194 if (!guest->load_template(guest, dir))
195 {
196 enumerator->destroy(enumerator);
197 clear_template(this);
198 return FALSE;
199 }
200 }
201 enumerator->destroy(enumerator);
202 return TRUE;
203 }
204
205 /**
206 * Implementation of dumm_t.destroy
207 */
208 static void destroy(private_dumm_t *this)
209 {
210 enumerator_t *enumerator;
211 guest_t *guest;
212
213 this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
214
215 enumerator = this->guests->create_enumerator(this->guests);
216 while (enumerator->enumerate(enumerator, (void**)&guest))
217 {
218 guest->stop(guest, NULL);
219 }
220 enumerator->destroy(enumerator);
221
222 this->destroying = TRUE;
223 this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy));
224 free(this->guest_dir);
225 free(this->template_dir);
226 free(this->template);
227 free(this->dir);
228 free(this);
229 }
230
231 /**
232 * load all guests in our working dir
233 */
234 static void load_guests(private_dumm_t *this)
235 {
236 DIR *dir;
237 struct dirent *ent;
238 guest_t *guest;
239
240 dir = opendir(this->guest_dir);
241 if (dir == NULL)
242 {
243 return;
244 }
245
246 while ((ent = readdir(dir)))
247 {
248 if (streq(ent->d_name, ".") || streq(ent->d_name, ".."))
249 {
250 continue;
251 }
252 guest = guest_load(this->guest_dir, ent->d_name);
253 if (guest)
254 {
255 this->guests->insert_last(this->guests, guest);
256 }
257 else
258 {
259 DBG1("loading guest in directory '%s' failed, skipped", ent->d_name);
260 }
261 }
262 closedir(dir);
263 }
264
265 /**
266 * create a dumm instance
267 */
268 dumm_t *dumm_create(char *dir)
269 {
270 char cwd[PATH_MAX];
271 private_dumm_t *this = malloc_thing(private_dumm_t);
272
273 this->public.create_guest = (guest_t*(*)(dumm_t*,char*,char*,char*,int))create_guest;
274 this->public.create_guest_enumerator = (enumerator_t*(*)(dumm_t*))create_guest_enumerator;
275 this->public.delete_guest = (void(*)(dumm_t*,guest_t*))delete_guest;
276 this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
277 this->public.create_bridge_enumerator = (enumerator_t*(*)(dumm_t*))create_bridge_enumerator;
278 this->public.delete_bridge = (void(*)(dumm_t*,bridge_t*))delete_bridge;
279 this->public.load_template = (bool(*)(dumm_t*, char *name))load_template;
280 this->public.destroy = (void(*)(dumm_t*))destroy;
281
282 this->destroying = FALSE;
283
284 if (dir && *dir == '/')
285 {
286 this->dir = strdup(dir);
287 }
288 else
289 {
290 if (getcwd(cwd, sizeof(cwd)) == NULL)
291 {
292 free(this);
293 return NULL;
294 }
295 if (dir)
296 {
297 asprintf(&this->dir, "%s/%s", cwd, dir);
298 }
299 else
300 {
301 this->dir = strdup(cwd);
302 }
303 }
304 this->template = NULL;
305 asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR);
306 asprintf(&this->template_dir, "%s/%s", this->dir, TEMPLATE_DIR);
307 this->guests = linked_list_create();
308 this->bridges = linked_list_create();
309
310 if (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST)
311 {
312 DBG1("creating guest directory '%s' failed: %m", this->guest_dir);
313 destroy(this);
314 return NULL;
315 }
316 if (mkdir(this->template_dir, PERME) < 0 && errno != EEXIST)
317 {
318 DBG1("creating template directory '%s' failed: %m", this->template_dir);
319 destroy(this);
320 return NULL;
321 }
322
323 load_guests(this);
324 return &this->public;
325 }
326